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

extern crate user32;
extern crate kernel32;
extern crate winapi;
extern crate gdi32;

use Scale;
use Vsync;
use Key;

use std::ptr;
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
use std::mem;

use self::winapi::windef::HWND;
use self::winapi::windef::HDC;
use self::winapi::winuser::WS_OVERLAPPEDWINDOW;
use self::winapi::winuser::WNDCLASSW;
use self::winapi::wingdi::BITMAPINFOHEADER;
use self::winapi::wingdi::RGBQUAD;

// Wrap this so we can have a proper numbef of bmiColors to write in
#[repr(C)]
struct BitmapInfo {
    pub bmi_header: BITMAPINFOHEADER,
    pub bmi_colors: [RGBQUAD; 3],
}

fn update_key_state(window: &mut Window, wparam: u32, state: bool) {
    match wparam & 0x1ff {
        0x00B => window.keys[Key::Key0 as usize] = state,
        0x002 => window.keys[Key::Key1 as usize] = state,
        0x003 => window.keys[Key::Key2 as usize] = state,
        0x004 => window.keys[Key::Key3 as usize] = state,
        0x005 => window.keys[Key::Key4 as usize] = state,
        0x006 => window.keys[Key::Key5 as usize] = state,
        0x007 => window.keys[Key::Key6 as usize] = state,
        0x008 => window.keys[Key::Key7 as usize] = state,
        0x009 => window.keys[Key::Key8 as usize] = state,
        0x00A => window.keys[Key::Key9 as usize] = state,
        0x01E => window.keys[Key::A as usize] = state,
        0x030 => window.keys[Key::B as usize] = state,
        0x02E => window.keys[Key::C as usize] = state,
        0x020 => window.keys[Key::D as usize] = state,
        0x012 => window.keys[Key::E as usize] = state,
        0x021 => window.keys[Key::F as usize] = state,
        0x022 => window.keys[Key::G as usize] = state,
        0x023 => window.keys[Key::H as usize] = state,
        0x017 => window.keys[Key::I as usize] = state,
        0x024 => window.keys[Key::J as usize] = state,
        0x025 => window.keys[Key::K as usize] = state,
        0x026 => window.keys[Key::L as usize] = state,
        0x032 => window.keys[Key::M as usize] = state,
        0x031 => window.keys[Key::N as usize] = state,
        0x018 => window.keys[Key::O as usize] = state,
        0x019 => window.keys[Key::P as usize] = state,
        0x010 => window.keys[Key::Q as usize] = state,
        0x013 => window.keys[Key::R as usize] = state,
        0x01F => window.keys[Key::S as usize] = state,
        0x014 => window.keys[Key::T as usize] = state,
        0x016 => window.keys[Key::U as usize] = state,
        0x02F => window.keys[Key::V as usize] = state,
        0x011 => window.keys[Key::W as usize] = state,
        0x02D => window.keys[Key::X as usize] = state,
        0x015 => window.keys[Key::Y as usize] = state,
        0x02C => window.keys[Key::Z as usize] = state,
        0x03B => window.keys[Key::F1 as usize] = state,
        0x03C => window.keys[Key::F2 as usize] = state,
        0x03D => window.keys[Key::F3 as usize] = state,
        0x03E => window.keys[Key::F4 as usize] = state,
        0x03F => window.keys[Key::F5 as usize] = state,
        0x040 => window.keys[Key::F6 as usize] = state,
        0x041 => window.keys[Key::F7 as usize] = state,
        0x042 => window.keys[Key::F8 as usize] = state,
        0x043 => window.keys[Key::F9 as usize] = state,
        0x044 => window.keys[Key::F10 as usize] = state,
        0x057 => window.keys[Key::F11 as usize] = state,
        0x058 => window.keys[Key::F12 as usize] = state,
        0x150 => window.keys[Key::Down as usize] = state,
        0x14B => window.keys[Key::Left as usize] = state,
        0x14D => window.keys[Key::Right as usize] = state,
        0x148 => window.keys[Key::Up as usize] = state,
        0x028 => window.keys[Key::Apostrophe as usize] = state,
        0x02B => window.keys[Key::Backslash as usize] = state,
        0x033 => window.keys[Key::Comma as usize] = state,
        0x00D => window.keys[Key::Equal as usize] = state,
        0x01A => window.keys[Key::LeftBracket as usize] = state,
        0x00C => window.keys[Key::Minus as usize] = state,
        0x034 => window.keys[Key::Period as usize] = state,
        0x01B => window.keys[Key::RightBracket as usize] = state,
        0x027 => window.keys[Key::Semicolon as usize] = state,
        0x035 => window.keys[Key::Slash as usize] = state,
        0x00E => window.keys[Key::Backspace as usize] = state,
        0x153 => window.keys[Key::Delete as usize] = state,
        0x14F => window.keys[Key::End as usize] = state,
        0x01C => window.keys[Key::Enter as usize] = state,
        0x001 => window.keys[Key::Escape as usize] = state,
        0x147 => window.keys[Key::Home as usize] = state,
        0x152 => window.keys[Key::Insert as usize] = state,
        0x15D => window.keys[Key::Menu as usize] = state,
        0x151 => window.keys[Key::PageDown as usize] = state,
        0x149 => window.keys[Key::PageUp as usize] = state,
        0x045 => window.keys[Key::Pause as usize] = state,
        0x039 => window.keys[Key::Space as usize] = state,
        0x00F => window.keys[Key::Tab as usize] = state,
        0x03A => window.keys[Key::CapsLock as usize] = state,
        _ => (),
    }
}

unsafe extern "system" fn wnd_proc(window: winapi::HWND,
                                   msg: winapi::UINT,
                                   wparam: winapi::WPARAM,
                                   lparam: winapi::LPARAM)
                                   -> winapi::LRESULT {
    // This make sure we actually don't do anything before the user data has been setup for the
    // window

    let user_data = user32::GetWindowLongPtrW(window, winapi::winuser::GWLP_USERDATA);

    if user_data == 0 {
        return user32::DefWindowProcW(window, msg, wparam, lparam);
    }

    let mut wnd: &mut Window = mem::transmute(user_data);

    match msg {
        winapi::winuser::WM_KEYDOWN => {
            update_key_state(wnd, (lparam as u32) >> 16, true);
        }

        winapi::winuser::WM_CLOSE => {
            wnd.is_open = false;
        }

        winapi::winuser::WM_KEYUP => {
            update_key_state(wnd, (lparam as u32) >> 16, false);
        }

        winapi::winuser::WM_PAINT => {
            let mut rect: winapi::RECT = mem::uninitialized();

            user32::GetClientRect(window, &mut rect);

            let mut bitmap_info: BitmapInfo = mem::zeroed();
            let width = rect.right - rect.left;
            let height = rect.bottom - rect.top;

            bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
            bitmap_info.bmi_header.biPlanes = 1;
            bitmap_info.bmi_header.biBitCount = 32;
            bitmap_info.bmi_header.biCompression = winapi::wingdi::BI_BITFIELDS;
            bitmap_info.bmi_header.biWidth = width;
            bitmap_info.bmi_header.biHeight = -height;
            bitmap_info.bmi_colors[0].rgbRed = 0xff;
            bitmap_info.bmi_colors[1].rgbGreen = 0xff;
            bitmap_info.bmi_colors[2].rgbBlue = 0xff;

            gdi32::StretchDIBits(wnd.dc.unwrap(),
                                 0,
                                 0,
                                 width,
                                 height,
                                 0,
                                 0,
                                 width,
                                 height,
                                 mem::transmute(wnd.buffer.as_ptr()),
                                 mem::transmute(&bitmap_info),
                                 winapi::wingdi::DIB_RGB_COLORS,
                                 winapi::wingdi::SRCCOPY);

            user32::ValidateRect(window, ptr::null_mut());
        }

        _ => (),
    }

    return user32::DefWindowProcW(window, msg, wparam, lparam);
}

pub enum MinifbError {
    UnableToCreateWindow,
}

fn to_wstring(str: &str) -> *const u16 {
    let v: Vec<u16> = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
    v.as_ptr()
}

pub struct Window {
    dc: Option<HDC>,
    window: Option<HWND>,
    keys: [bool; 512],
    buffer: Vec<u32>,
    is_open : bool,
}

impl Window {
    fn open_window(name: &str, width: usize, height: usize, _: Scale, _: Vsync) -> Option<HWND> {
        unsafe {
            let class_name = to_wstring("minifb_window");

            let class = WNDCLASSW {
                style: winapi::CS_HREDRAW | winapi::CS_VREDRAW | winapi::CS_OWNDC,
                lpfnWndProc: Some(wnd_proc),
                cbClsExtra: 0,
                cbWndExtra: 0,
                hInstance: kernel32::GetModuleHandleA(ptr::null()),
                hIcon: ptr::null_mut(),
                hCursor: ptr::null_mut(),
                hbrBackground: ptr::null_mut(),
                lpszMenuName: ptr::null(),
                lpszClassName: class_name,
            };

            if user32::RegisterClassW(&class) == 0 {
                println!("Unable to register class, error {}", kernel32::GetLastError() as u32);
                return None;
            }

            let mut rect = winapi::RECT {
                left: 0,
                right: width as winapi::LONG,
                top: 0,
                bottom: height as winapi::LONG,
            };

            user32::AdjustWindowRect(&mut rect,
                                     winapi::WS_POPUP | winapi::WS_SYSMENU | winapi::WS_CAPTION,
                                     0);

            rect.right -= rect.left;
            rect.bottom -= rect.top;

            let handle = user32::CreateWindowExW(0,
                                                 class_name,
                                                 to_wstring(name),
                                                 winapi::WS_OVERLAPPEDWINDOW &
                                                 !winapi::WS_MAXIMIZEBOX &
                                                 !winapi::WS_THICKFRAME,
                                                 winapi::CW_USEDEFAULT,
                                                 winapi::CW_USEDEFAULT,
                                                 rect.right,
                                                 rect.bottom,
                                                 ptr::null_mut(),
                                                 ptr::null_mut(),
                                                 ptr::null_mut(),
                                                 ptr::null_mut());
            if handle.is_null() {
                println!("Unable to create window, error {}", kernel32::GetLastError() as u32);
                return None;
            }

            user32::ShowWindow(handle, winapi::SW_NORMAL);

            return Some(handle);
        }
    }

    pub fn new(name: &str,
               width: usize,
               height: usize,
               scale: Scale,
               vsync: Vsync)
               -> Result<Window, &str> {
        unsafe {
            let handle = Self::open_window(name, width, height, scale, vsync);

            if handle.is_none() {
                return Err("Unable to create Window");
            }

            let window = Window {
                dc: Some(user32::GetDC(handle.unwrap())),
                window: Some(handle.unwrap()),
                keys: [false; 512],
                buffer: Vec::new(),
                is_open: true,
            };

            Ok(window)
        }
    }

    #[inline]
    pub fn is_key_down(&self, key: Key) -> bool {
        return self.keys[key as usize];
    }

    #[inline]
    pub fn is_open(&self) -> bool {
        return self.is_open
    }

    pub fn update(&mut self, buffer: &[u32]) {
        unsafe {
            let mut msg = mem::uninitialized();
            let window = self.window.unwrap();

            // TODO: Optimize

            self.buffer = buffer.iter().cloned().collect();

            user32::SetWindowLongPtrW(window, winapi::winuser::GWLP_USERDATA, mem::transmute(self));
            user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE);

            while user32::PeekMessageW(&mut msg, window, 0, 0, winapi::winuser::PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }
        }
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.dc.is_some() {
                user32::ReleaseDC(self.window.unwrap(), self.dc.unwrap());
            }

            if self.window.is_some() {
                user32::CloseWindow(self.window.unwrap());
            }
        }
    }
}
<commit_msg>Null terminate wchar string<commit_after>#![cfg(target_os = "windows")]

extern crate user32;
extern crate kernel32;
extern crate winapi;
extern crate gdi32;

use Scale;
use Vsync;
use Key;

use std::ptr;
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
use std::mem;

use self::winapi::windef::HWND;
use self::winapi::windef::HDC;
use self::winapi::winuser::WS_OVERLAPPEDWINDOW;
use self::winapi::winuser::WNDCLASSW;
use self::winapi::wingdi::BITMAPINFOHEADER;
use self::winapi::wingdi::RGBQUAD;

// Wrap this so we can have a proper numbef of bmiColors to write in
#[repr(C)]
struct BitmapInfo {
    pub bmi_header: BITMAPINFOHEADER,
    pub bmi_colors: [RGBQUAD; 3],
}

fn update_key_state(window: &mut Window, wparam: u32, state: bool) {
    match wparam & 0x1ff {
        0x00B => window.keys[Key::Key0 as usize] = state,
        0x002 => window.keys[Key::Key1 as usize] = state,
        0x003 => window.keys[Key::Key2 as usize] = state,
        0x004 => window.keys[Key::Key3 as usize] = state,
        0x005 => window.keys[Key::Key4 as usize] = state,
        0x006 => window.keys[Key::Key5 as usize] = state,
        0x007 => window.keys[Key::Key6 as usize] = state,
        0x008 => window.keys[Key::Key7 as usize] = state,
        0x009 => window.keys[Key::Key8 as usize] = state,
        0x00A => window.keys[Key::Key9 as usize] = state,
        0x01E => window.keys[Key::A as usize] = state,
        0x030 => window.keys[Key::B as usize] = state,
        0x02E => window.keys[Key::C as usize] = state,
        0x020 => window.keys[Key::D as usize] = state,
        0x012 => window.keys[Key::E as usize] = state,
        0x021 => window.keys[Key::F as usize] = state,
        0x022 => window.keys[Key::G as usize] = state,
        0x023 => window.keys[Key::H as usize] = state,
        0x017 => window.keys[Key::I as usize] = state,
        0x024 => window.keys[Key::J as usize] = state,
        0x025 => window.keys[Key::K as usize] = state,
        0x026 => window.keys[Key::L as usize] = state,
        0x032 => window.keys[Key::M as usize] = state,
        0x031 => window.keys[Key::N as usize] = state,
        0x018 => window.keys[Key::O as usize] = state,
        0x019 => window.keys[Key::P as usize] = state,
        0x010 => window.keys[Key::Q as usize] = state,
        0x013 => window.keys[Key::R as usize] = state,
        0x01F => window.keys[Key::S as usize] = state,
        0x014 => window.keys[Key::T as usize] = state,
        0x016 => window.keys[Key::U as usize] = state,
        0x02F => window.keys[Key::V as usize] = state,
        0x011 => window.keys[Key::W as usize] = state,
        0x02D => window.keys[Key::X as usize] = state,
        0x015 => window.keys[Key::Y as usize] = state,
        0x02C => window.keys[Key::Z as usize] = state,
        0x03B => window.keys[Key::F1 as usize] = state,
        0x03C => window.keys[Key::F2 as usize] = state,
        0x03D => window.keys[Key::F3 as usize] = state,
        0x03E => window.keys[Key::F4 as usize] = state,
        0x03F => window.keys[Key::F5 as usize] = state,
        0x040 => window.keys[Key::F6 as usize] = state,
        0x041 => window.keys[Key::F7 as usize] = state,
        0x042 => window.keys[Key::F8 as usize] = state,
        0x043 => window.keys[Key::F9 as usize] = state,
        0x044 => window.keys[Key::F10 as usize] = state,
        0x057 => window.keys[Key::F11 as usize] = state,
        0x058 => window.keys[Key::F12 as usize] = state,
        0x150 => window.keys[Key::Down as usize] = state,
        0x14B => window.keys[Key::Left as usize] = state,
        0x14D => window.keys[Key::Right as usize] = state,
        0x148 => window.keys[Key::Up as usize] = state,
        0x028 => window.keys[Key::Apostrophe as usize] = state,
        0x02B => window.keys[Key::Backslash as usize] = state,
        0x033 => window.keys[Key::Comma as usize] = state,
        0x00D => window.keys[Key::Equal as usize] = state,
        0x01A => window.keys[Key::LeftBracket as usize] = state,
        0x00C => window.keys[Key::Minus as usize] = state,
        0x034 => window.keys[Key::Period as usize] = state,
        0x01B => window.keys[Key::RightBracket as usize] = state,
        0x027 => window.keys[Key::Semicolon as usize] = state,
        0x035 => window.keys[Key::Slash as usize] = state,
        0x00E => window.keys[Key::Backspace as usize] = state,
        0x153 => window.keys[Key::Delete as usize] = state,
        0x14F => window.keys[Key::End as usize] = state,
        0x01C => window.keys[Key::Enter as usize] = state,
        0x001 => window.keys[Key::Escape as usize] = state,
        0x147 => window.keys[Key::Home as usize] = state,
        0x152 => window.keys[Key::Insert as usize] = state,
        0x15D => window.keys[Key::Menu as usize] = state,
        0x151 => window.keys[Key::PageDown as usize] = state,
        0x149 => window.keys[Key::PageUp as usize] = state,
        0x045 => window.keys[Key::Pause as usize] = state,
        0x039 => window.keys[Key::Space as usize] = state,
        0x00F => window.keys[Key::Tab as usize] = state,
        0x03A => window.keys[Key::CapsLock as usize] = state,
        _ => (),
    }
}

unsafe extern "system" fn wnd_proc(window: winapi::HWND,
                                   msg: winapi::UINT,
                                   wparam: winapi::WPARAM,
                                   lparam: winapi::LPARAM)
                                   -> winapi::LRESULT {
    // This make sure we actually don't do anything before the user data has been setup for the
    // window

    let user_data = user32::GetWindowLongPtrW(window, winapi::winuser::GWLP_USERDATA);

    if user_data == 0 {
        return user32::DefWindowProcW(window, msg, wparam, lparam);
    }

    let mut wnd: &mut Window = mem::transmute(user_data);

    match msg {
        winapi::winuser::WM_KEYDOWN => {
            update_key_state(wnd, (lparam as u32) >> 16, true);
        }

        winapi::winuser::WM_CLOSE => {
            wnd.is_open = false;
        }

        winapi::winuser::WM_KEYUP => {
            update_key_state(wnd, (lparam as u32) >> 16, false);
        }

        winapi::winuser::WM_PAINT => {
            let mut rect: winapi::RECT = mem::uninitialized();

            user32::GetClientRect(window, &mut rect);

            let mut bitmap_info: BitmapInfo = mem::zeroed();
            let width = rect.right - rect.left;
            let height = rect.bottom - rect.top;

            bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
            bitmap_info.bmi_header.biPlanes = 1;
            bitmap_info.bmi_header.biBitCount = 32;
            bitmap_info.bmi_header.biCompression = winapi::wingdi::BI_BITFIELDS;
            bitmap_info.bmi_header.biWidth = width;
            bitmap_info.bmi_header.biHeight = -height;
            bitmap_info.bmi_colors[0].rgbRed = 0xff;
            bitmap_info.bmi_colors[1].rgbGreen = 0xff;
            bitmap_info.bmi_colors[2].rgbBlue = 0xff;

            gdi32::StretchDIBits(wnd.dc.unwrap(),
                                 0,
                                 0,
                                 width,
                                 height,
                                 0,
                                 0,
                                 width,
                                 height,
                                 mem::transmute(wnd.buffer.as_ptr()),
                                 mem::transmute(&bitmap_info),
                                 winapi::wingdi::DIB_RGB_COLORS,
                                 winapi::wingdi::SRCCOPY);

            user32::ValidateRect(window, ptr::null_mut());
        }

        _ => (),
    }

    return user32::DefWindowProcW(window, msg, wparam, lparam);
}

pub enum MinifbError {
    UnableToCreateWindow,
}

fn to_wstring(str: &str) -> *const u16 {
    let mut v: Vec<u16> = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
    v.push(0u16);
    v.as_ptr()
}

pub struct Window {
    dc: Option<HDC>,
    window: Option<HWND>,
    keys: [bool; 512],
    buffer: Vec<u32>,
    is_open : bool,
}

impl Window {
    fn open_window(name: &str, width: usize, height: usize, _: Scale, _: Vsync) -> Option<HWND> {
        unsafe {
            let class_name = to_wstring("minifb_window");
            let class = WNDCLASSW {
                style: winapi::CS_HREDRAW | winapi::CS_VREDRAW | winapi::CS_OWNDC,
                lpfnWndProc: Some(wnd_proc),
                cbClsExtra: 0,
                cbWndExtra: 0,
                hInstance: kernel32::GetModuleHandleA(ptr::null()),
                hIcon: ptr::null_mut(),
                hCursor: ptr::null_mut(),
                hbrBackground: ptr::null_mut(),
                lpszMenuName: ptr::null(),
                lpszClassName: class_name,
            };

            if user32::RegisterClassW(&class) == 0 {
                println!("Unable to register class, error {}", kernel32::GetLastError() as u32);
                return None;
            }

            let mut rect = winapi::RECT {
                left: 0,
                right: width as winapi::LONG,
                top: 0,
                bottom: height as winapi::LONG,
            };

            user32::AdjustWindowRect(&mut rect,
                                     winapi::WS_POPUP | winapi::WS_SYSMENU | winapi::WS_CAPTION,
                                     0);

            rect.right -= rect.left;
            rect.bottom -= rect.top;

            let handle = user32::CreateWindowExW(0,
                                                 class_name,
                                                 to_wstring(name),
                                                 winapi::WS_OVERLAPPEDWINDOW &
                                                 !winapi::WS_MAXIMIZEBOX &
                                                 !winapi::WS_THICKFRAME,
                                                 winapi::CW_USEDEFAULT,
                                                 winapi::CW_USEDEFAULT,
                                                 rect.right,
                                                 rect.bottom,
                                                 ptr::null_mut(),
                                                 ptr::null_mut(),
                                                 ptr::null_mut(),
                                                 ptr::null_mut());
            if handle.is_null() {
                println!("Unable to create window, error {}", kernel32::GetLastError() as u32);
                return None;
            }

            user32::ShowWindow(handle, winapi::SW_NORMAL);

            return Some(handle);
        }
    }

    pub fn new(name: &str,
               width: usize,
               height: usize,
               scale: Scale,
               vsync: Vsync)
               -> Result<Window, &str> {
        unsafe {
            let handle = Self::open_window(name, width, height, scale, vsync);

            if handle.is_none() {
                return Err("Unable to create Window");
            }

            let window = Window {
                dc: Some(user32::GetDC(handle.unwrap())),
                window: Some(handle.unwrap()),
                keys: [false; 512],
                buffer: Vec::new(),
                is_open: true,
            };

            Ok(window)
        }
    }

    #[inline]
    pub fn is_key_down(&self, key: Key) -> bool {
        return self.keys[key as usize];
    }

    #[inline]
    pub fn is_open(&self) -> bool {
        return self.is_open
    }

    pub fn update(&mut self, buffer: &[u32]) {
        unsafe {
            let mut msg = mem::uninitialized();
            let window = self.window.unwrap();

            // TODO: Optimize

            self.buffer = buffer.iter().cloned().collect();

            user32::SetWindowLongPtrW(window, winapi::winuser::GWLP_USERDATA, mem::transmute(self));
            user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE);

            while user32::PeekMessageW(&mut msg, window, 0, 0, winapi::winuser::PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }
        }
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.dc.is_some() {
                user32::ReleaseDC(self.window.unwrap(), self.dc.unwrap());
            }

            if self.window.is_some() {
                user32::CloseWindow(self.window.unwrap());
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// 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/.

use std::io;
use std::thread;

use fsuipc;
use fsuipc::{Handle, Session};
use mio;

use domain::types::*;
use util::Consume;

pub mod types;
pub use self::types::*;

const POLLING_DELAY_MS: u64 = 50;

#[derive(Debug)]
pub enum Envelope {
    Cmd(Command),
    Shutdown
}

pub struct Domain {
    worker: thread::JoinHandle<()>,
    tx: mio::Sender<Envelope>
}

impl Domain {
    pub fn new() -> Domain {
        let (worker, tx) = spawn_worker();
        Domain { worker: worker, tx: tx }
    }

    pub fn shutdown(self) {
        self.tx.send(Envelope::Shutdown).unwrap_or_else(|e| {
            warn!("unexpected error while sending shutdown message to fsuipc domain: {}", e);
        });
        self.worker.join().unwrap_or_else(|_| {
            warn!("unexpected error while waiting for fsuipc domain worker thread");
        });
    }

    pub fn consumer(&self) -> Consumer {
        Consumer { tx: self.tx.clone() }
    }
}

#[derive(Clone)]
pub struct Consumer {
    tx: mio::Sender<Envelope>
}

impl Consume for Consumer {
    type Item = Command;
    type Error = mio::NotifyError<Envelope>;
    fn consume(&mut self, cmd: Command) -> Result<(), mio::NotifyError<Envelope>> {
        self.tx.send(Envelope::Cmd(cmd))
    }
}

struct Observer {
    offset: Offset,
    client: Client,
    retain: Option<Value>,
    buffer: [u8; 4],
}

impl Observer {
    pub fn read(&mut self, session: &mut fsuipc::local::LocalSession) {
        let offset = u16::from(self.offset.addr());
        let buffer = &mut self.buffer as *mut [u8; 4] as *mut u8;
        let nbytes = usize::from(self.offset.len());
        if let Err(e) = session.read_bytes(offset, buffer, nbytes) {
            error!("unexpected error while reading bytes from FSUIPC session: {}", e);
        }
    }

    pub fn trigger_event(&mut self) {
        let buf_value = self.offset.len().decode_value(&self.buffer);
        let must_trigger = self.retain.as_ref().map(|v| *v != buf_value).unwrap_or(true);
        if must_trigger {
            let event = Event::Update(Var::FsuipcOffset(self.offset), buf_value);
            debug!("triggering event {:?} to client {}", event, self.client.name());
            if let Err(e) = self.client.sender().send(event) {
                error!("expected error while sending event to client {}: {}",
                    self.client.name(), e);
            }
            self.retain = Some(buf_value);
        }
    }
}

struct Context {
    handle: fsuipc::local::LocalHandle,
    observers: Vec<Observer>,
}

impl Context {
    pub fn new()  -> io::Result<Context> {
        Ok(Context {
            handle: try!(fsuipc::local::LocalHandle::new()),
            observers: Vec::new(),
        })
    }

    fn process_write(&mut self, offset: Offset, value: Value) -> io::Result<()> {
        debug!("writing value {} to offset {}", value, offset);
        match offset.len() {
            OffsetLen::UnsignedByte => self.process_write_of(offset.addr(), u8::from(value)),
            OffsetLen::SignedByte => self.process_write_of(offset.addr(), i8::from(value)),
            OffsetLen::UnsignedWord => self.process_write_of(offset.addr(), u16::from(value)),
            OffsetLen::SignedWord => self.process_write_of(offset.addr(), i16::from(value)),
            OffsetLen::UnsignedDouble => self.process_write_of(offset.addr(), u32::from(value)),
            OffsetLen::SignedDouble => self.process_write_of(offset.addr(), i32::from(value)),
        }
    }

    fn process_obs(&mut self, offset: Offset, client: Client) {
        debug!("client {} observing offset {}", client.name(), offset);
        self.observers.push(Observer {
            offset: offset,
            client: client,
            retain: None,
            buffer: [0; 4]
        });
    }

    fn process_write_of<T>(&mut self, offset: OffsetAddr, value: T) -> io::Result<()> {
        let mut session = self.handle.session();
        try!(session.write(u16::from(offset), &value));
        try!(session.process());
        Ok(())
    }
}

fn spawn_worker() -> (thread::JoinHandle<()>, mio::Sender<Envelope>) {
    let event_loop = mio::EventLoop::new().unwrap();
    let tx = event_loop.channel();
    let worker = thread::spawn(move || {
        let mut event_loop = event_loop;
        let mut ctx = match Context::new() {
            Ok(ctx) => ctx,
            Err(e) => {
                error!("cannot create FSUIPC context (is FSUIPC installed & running?): {}", e);
                return;
            },
        };
        event_loop.timeout_ms((), POLLING_DELAY_MS).unwrap();
        event_loop.run(&mut ctx).unwrap();
    });
    (worker, tx)
}

impl mio::Handler for Context {
    type Timeout = ();
    type Message = Envelope;

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Context>, _: ()) {
        let mut session = self.handle.session();
        for obs in self.observers.iter_mut() {
            obs.read(&mut session);
        }
        session.process().unwrap();
        for obs in self.observers.iter_mut() {
            obs.trigger_event();
        }
        event_loop.timeout_ms((), POLLING_DELAY_MS).unwrap();
    }

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Context>, msg: Envelope) {
        match msg {
            Envelope::Cmd(Command::Write(Var::FsuipcOffset(offset), value)) => {
                if let Err(e) = self.process_write(offset, value) {
                    error!("unexpected IO error while processing write command: {}", e);
                }
            },
            Envelope::Cmd(Command::Observe(Var::FsuipcOffset(offset), client)) => {
                self.process_obs(offset, client)
            },
            Envelope::Shutdown => event_loop.shutdown(),
            other => {
                warn!("fsuipc domain received an unexpected message: {:?}", other);
            },
        }
    }
}

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

    #[test]
    fn should_init_and_shutdown() {
        let mut domain = Domain::new();
        domain.shutdown();
    }
}
<commit_msg>Improve logging messages in `fsuipc` domain<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// 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/.

use std::io;
use std::thread;

use fsuipc;
use fsuipc::{Handle, Session};
use mio;

use domain::types::*;
use util::Consume;

pub mod types;
pub use self::types::*;

const POLLING_DELAY_MS: u64 = 50;

#[derive(Debug)]
pub enum Envelope {
    Cmd(Command),
    Shutdown
}

pub struct Domain {
    worker: thread::JoinHandle<()>,
    tx: mio::Sender<Envelope>
}

impl Domain {
    pub fn new() -> Domain {
        let (worker, tx) = spawn_worker();
        Domain { worker: worker, tx: tx }
    }

    pub fn shutdown(self) {
        self.tx.send(Envelope::Shutdown).unwrap_or_else(|e| {
            warn!("unexpected error while sending shutdown message to FSUIPC domain: {}", e);
        });
        self.worker.join().unwrap_or_else(|_| {
            warn!("unexpected error while waiting for FSUIPC domain worker thread");
        });
    }

    pub fn consumer(&self) -> Consumer {
        Consumer { tx: self.tx.clone() }
    }
}

#[derive(Clone)]
pub struct Consumer {
    tx: mio::Sender<Envelope>
}

impl Consume for Consumer {
    type Item = Command;
    type Error = mio::NotifyError<Envelope>;
    fn consume(&mut self, cmd: Command) -> Result<(), mio::NotifyError<Envelope>> {
        self.tx.send(Envelope::Cmd(cmd))
    }
}

struct Observer {
    offset: Offset,
    client: Client,
    retain: Option<Value>,
    buffer: [u8; 4],
}

impl Observer {
    pub fn read(&mut self, session: &mut fsuipc::local::LocalSession) {
        let offset = u16::from(self.offset.addr());
        let buffer = &mut self.buffer as *mut [u8; 4] as *mut u8;
        let nbytes = usize::from(self.offset.len());
        if let Err(e) = session.read_bytes(offset, buffer, nbytes) {
            error!("unexpected error while reading bytes from FSUIPC session: {}", e);
        }
    }

    pub fn trigger_event(&mut self) {
        let buf_value = self.offset.len().decode_value(&self.buffer);
        let must_trigger = self.retain.as_ref().map(|v| *v != buf_value).unwrap_or(true);
        if must_trigger {
            let event = Event::Update(Var::FsuipcOffset(self.offset), buf_value);
            debug!("triggering event {:?} to client {}", event, self.client.name());
            if let Err(e) = self.client.sender().send(event) {
                error!("expected error while sending event to client {}: {}",
                    self.client.name(), e);
            }
            self.retain = Some(buf_value);
        }
    }
}

struct Context {
    handle: fsuipc::local::LocalHandle,
    observers: Vec<Observer>,
}

impl Context {
    pub fn new()  -> io::Result<Context> {
        Ok(Context {
            handle: try!(fsuipc::local::LocalHandle::new()),
            observers: Vec::new(),
        })
    }

    fn process_write(&mut self, offset: Offset, value: Value) -> io::Result<()> {
        debug!("writing value {} to offset {}", value, offset);
        match offset.len() {
            OffsetLen::UnsignedByte => self.process_write_of(offset.addr(), u8::from(value)),
            OffsetLen::SignedByte => self.process_write_of(offset.addr(), i8::from(value)),
            OffsetLen::UnsignedWord => self.process_write_of(offset.addr(), u16::from(value)),
            OffsetLen::SignedWord => self.process_write_of(offset.addr(), i16::from(value)),
            OffsetLen::UnsignedDouble => self.process_write_of(offset.addr(), u32::from(value)),
            OffsetLen::SignedDouble => self.process_write_of(offset.addr(), i32::from(value)),
        }
    }

    fn process_obs(&mut self, offset: Offset, client: Client) {
        debug!("client {} observing offset {}", client.name(), offset);
        self.observers.push(Observer {
            offset: offset,
            client: client,
            retain: None,
            buffer: [0; 4]
        });
    }

    fn process_write_of<T>(&mut self, offset: OffsetAddr, value: T) -> io::Result<()> {
        let mut session = self.handle.session();
        try!(session.write(u16::from(offset), &value));
        try!(session.process());
        Ok(())
    }
}

fn spawn_worker() -> (thread::JoinHandle<()>, mio::Sender<Envelope>) {
    let event_loop = mio::EventLoop::new().unwrap();
    let tx = event_loop.channel();
    let worker = thread::spawn(move || {
        let mut event_loop = event_loop;
        let mut ctx = match Context::new() {
            Ok(ctx) => ctx,
            Err(e) => {
                error!("cannot create FSUIPC context (is FSUIPC installed & running?): {}", e);
                return;
            },
        };
        event_loop.timeout_ms((), POLLING_DELAY_MS).unwrap();
        event_loop.run(&mut ctx).unwrap();
    });
    (worker, tx)
}

impl mio::Handler for Context {
    type Timeout = ();
    type Message = Envelope;

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Context>, _: ()) {
        let mut session = self.handle.session();
        for obs in self.observers.iter_mut() {
            obs.read(&mut session);
        }
        session.process().unwrap();
        for obs in self.observers.iter_mut() {
            obs.trigger_event();
        }
        event_loop.timeout_ms((), POLLING_DELAY_MS).unwrap();
    }

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Context>, msg: Envelope) {
        match msg {
            Envelope::Cmd(Command::Write(Var::FsuipcOffset(offset), value)) => {
                if let Err(e) = self.process_write(offset, value) {
                    error!("unexpected IO error while processing write command: {}", e);
                }
            },
            Envelope::Cmd(Command::Observe(Var::FsuipcOffset(offset), client)) => {
                self.process_obs(offset, client)
            },
            Envelope::Shutdown => {
                info!("shutting down FSUIPC domain event loop");
                event_loop.shutdown();
            },
            other => {
                warn!("FSUIPC domain received an unexpected message: {:?}", other);
            },
        }
    }
}

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

    #[test]
    fn should_init_and_shutdown() {
        let mut domain = Domain::new();
        domain.shutdown();
    }
}
<|endoftext|>


<commit_before>use eew::*;

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone, Copy)]
pub enum EEWPhase {
	Cancel,
	Forecast,
	Alert
}

impl EEW {

	pub fn get_eew_phase(&self) -> Option<EEWPhase>
	{
		match self.kind {

			Kind::Cancel | Kind::DrillCancel => Some(EEWPhase::Cancel),

			Kind::Normal | Kind::Drill | Kind::Reference | Kind::Test => {

				match self.detail.as_ref().map(|d| d.warning_status) {
					Some(WarningStatus::Alert) => Some(EEWPhase::Alert),
					Some(WarningStatus::Forecast) => Some(EEWPhase::Forecast),
					_ => None,
				}
			}
		}
	}

	pub fn is_high_accuracy(&self) -> bool
	{
		self.issue_pattern == IssuePattern::HighAccuracy
	}

	pub fn is_last(&self) -> bool
	{
		match self.status {
			Status::LastWithCorrection | Status::Last => true,
			_ => false
		}
	}

	pub fn is_drill(&self) -> bool
	{
		self.kind == Kind::Drill || self.kind == Kind::DrillCancel
	}
}
<commit_msg>EEWPhase: Add FastForecast phase<commit_after>use eew::*;

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone, Copy)]
pub enum EEWPhase {
	Cancel,
	FastForecast,
	Forecast,
	Alert
}

impl EEW {

	pub fn get_eew_phase(&self) -> Option<EEWPhase>
	{
		match self.kind {

			Kind::Cancel | Kind::DrillCancel => Some(EEWPhase::Cancel),

			Kind::Normal | Kind::Drill | Kind::Reference | Kind::Test => {

				match self.detail.as_ref().map(|d| d.warning_status) {
					Some(WarningStatus::Alert) => Some(EEWPhase::Alert),
					Some(WarningStatus::Forecast) => {
						match self.issue_pattern {
							IssuePattern::IntensityOnly => Some(EEWPhase::FastForecast),
							IssuePattern::LowAccuracy | IssuePattern::HighAccuracy => Some(EEWPhase::Forecast),
							_ => None,
						}
					}
					_ => None,
				}
			}
		}
	}

	pub fn is_high_accuracy(&self) -> bool
	{
		self.issue_pattern == IssuePattern::HighAccuracy
	}

	pub fn is_last(&self) -> bool
	{
		match self.status {
			Status::LastWithCorrection | Status::Last => true,
			_ => false
		}
	}

	pub fn is_drill(&self) -> bool
	{
		self.kind == Kind::Drill || self.kind == Kind::DrillCancel
	}
}
<|endoftext|>


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

use rand::random;

use parser::ast::{Function, Expr, ExprItem, Term, Statement};
use math::rich_number::{Unit, RichNumber};
use math::conversion_table::ConversionTable;

use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_tree_node::EvalTreeNode;

use eval::defaults as default_functions;

use prelude::setup_prelude;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
    ConversionUndefined {
        start: Unit,
        target: Unit,
    },
    InvalidParam(String),
}

pub type EvalResult = Result<ContextItem, EvalError>;

pub struct EvalContext {
    // Symbol name to context item definition
    symbol_table: HashMap<String, ContextItem>,
    // Unit to Symbol name
    units: HashMap<Unit, String>,
    // Used to define new units
    next_unit: Unit,
    conversion_table: ConversionTable,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
            units: HashMap::new(),
            next_unit: 1,
            conversion_table: ConversionTable::new(),
        }
    }

    /// Defines a reasonble set of default built_in methods
    pub fn defaults() -> EvalContext {
        let mut context = EvalContext::new();

        context.set_constant("PREFIX", Fixity::Prefix.to_string());
        context.set_constant("INFIX", Fixity::Infix.to_string());
        context.set_constant("POSTFIX", Fixity::Postfix.to_string());

        context.define_built_in_method_defaults(
            "operator",
            4,
            BuiltInFunction::new(default_functions::operator),
        );

        context.define_built_in_method_defaults(
            "defineUnit",
            1,
            BuiltInFunction::new(default_functions::define_unit),
        );

        context.define_built_in_method_defaults(
            "convert",
            2,
            BuiltInFunction::new(default_functions::convert),
        );

        context.define_built_in_method_defaults(
            "unitFor",
            1,
            BuiltInFunction::new(default_functions::unit_for),
        );

        context.define_built_in_method_defaults(
            "valueOf",
            1,
            BuiltInFunction::new(default_functions::value_of),
        );

        context.define_built_in_method_defaults(
            "conversion",
            3,
            BuiltInFunction::new(default_functions::conversion),
        );

        context
    }

    /// Defines a context with all the defaults as well as definitions
    /// for common operators and units
    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::defaults();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        self.set(name, ContextItem::new_definition(fixity, precedence, function));
    }

    /// Defines a function in the context with defaults for precedence and fixity
    pub fn define_defaults(
        &mut self,
        name: &str,
        function: Function,
    ) {
        self.set(name, ContextItem::function_defaults(function));
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_built_in_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: BuiltInFunction,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Defines a built-in function in the context with defaults for precedence and fixity
    pub fn define_built_in_method_defaults(
        &mut self,
        name: &str,
        params: usize,
        function: BuiltInFunction,
    ) {
        self.set(name, ContextItem::built_in_defaults(function, params));
    }

    /// Creates a unique identifier for the given unit name
    /// Calling this more than once for the same unit name will end up
    /// with some duplicate definitons, should not be a huge deal but may
    /// lead to problems later on
    pub fn create_unit(&mut self, name: &str) -> Unit {
        let unit = self.next_unit;
        self.next_unit += 1;

        self.units.insert(unit, name.to_owned());

        unit
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    /// Removes a name from the context, does nothing if name is not there
    pub fn remove(&mut self, name: &str) {
        self.symbol_table.remove(name);
    }

    /// Converts the value to the given unit by doing appropriate
    /// transformations as prescribed by the conversion table
    /// Returns Err if no appropriate conversion is found
    pub fn convert(&mut self, value: RichNumber, unit: Option<Unit>) -> EvalResult {
        if value.unit.is_none() || unit.is_none() {
            Ok(ContextItem::Number(RichNumber::new(value.value, unit)))
        }
        else {
            let start = value.unit.unwrap();
            let unit = unit.unwrap();

            let conversions = self.conversion_table.conversion_steps(start, unit);

            if conversions.is_none() {
                Err(EvalError::ConversionUndefined {
                    start: start,
                    target: unit,
                })
            }
            else {
                let conversions = conversions.unwrap();

                let mut current = ContextItem::Number(value);
                for next_unit in conversions {
                    //TODO: unwrap_number() here may not be completely safe
                    //TODO: because it is dependent on the result of applying the converter
                    let current_number = current.unwrap_number();

                    // unwrap() is safe here because we used conversion_steps
                    let converter = self.conversion_table.get_converter(
                        current_number.unit.unwrap(),
                        next_unit
                    ).unwrap();

                    current = try!(self.apply_function(&converter, vec![
                        ContextItem::Number(current_number.without_units()),
                    ]));
                }

                debug_assert!({
                    let c = current.clone().unwrap_number().unit;
                    !c.is_none() && c.unwrap() == unit
                });

                Ok(current)
            }
        }
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define_defaults(&name, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        self.reduce(root)
    }

    fn reduce(&mut self, node: EvalTreeNode) -> EvalResult {
        let EvalTreeNode {
            item,
            children,
        } = node;

        let mut params = Vec::new();
        for child in children {
            params.push(try!(self.reduce(child)));
        }

        // Special case: when no parameters are provided, return
        // the function itself.
        // Added to support (f) and anonymous syntax
        if item.is_function() && params.is_empty() {
            return Ok(item.clone())
        }

        match item {
            ContextItem::BuiltInMethod { ref function, params: ref pn, .. } => {
                debug_assert!(!params.is_empty());

                debug_assert!(*pn != 0,
                    "Functions cannot have zero parameters");

                function.call(self, params)
            },
            ContextItem::Definition { ref function, .. } => {
                debug_assert!(!params.is_empty());
                self.apply_function(function, params)
            },
            otherwise => Ok(otherwise),
        }
    }

    /// Applies the given parameters to the given function
    fn apply_function(&mut self, function: &Function, params: Vec<ContextItem>) -> EvalResult {
        let param_names = &function.params;
        if params.len() != param_names.len() {
            return Err(EvalError::ExpectedParams(param_names.len()));
        }

        // need to munge parameter names
        // one day this will be replaced with a true stack
        // using characters that couldn't possibly be in any other symbol
        let munge = format!("[[{}]]", random::<u64>());

        let reserved_names = param_names.iter()
            .map(|n| (n.clone(), format!("{}{}", munge, n)))
            .collect::<HashMap<String, String>>();

        let body: Expr = self.munge_expr(&function.body, reserved_names);

        unimplemented!();
    }

    fn munge_expr(&self, expr: &Expr, reserved_names: HashMap<String, String>) -> Expr {
        expr.iter().map(|x| {
            if let ExprItem::SingleTerm(Term::Symbol(ref name)) = *x {
                if reserved_names.contains_key(name) {
                    let new_name = reserved_names.get(name).unwrap().clone();
                    ExprItem::SingleTerm(Term::Symbol(new_name))
                }
                else {
                    x.clone()
                }
            }
            else {
                x.clone()
            }
        }).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use api::parse;

    use ast::*;
    use math::rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::prelude();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<commit_msg>Finished apply_function<commit_after>use std::collections::HashMap;

use rand::random;

use parser::ast::{Function, Expr, ExprItem, Term, Statement};
use math::rich_number::{Unit, RichNumber};
use math::conversion_table::ConversionTable;

use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_tree_node::EvalTreeNode;

use eval::defaults as default_functions;

use prelude::setup_prelude;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
    ConversionUndefined {
        start: Unit,
        target: Unit,
    },
    InvalidParam(String),
}

pub type EvalResult = Result<ContextItem, EvalError>;

pub struct EvalContext {
    // Symbol name to context item definition
    symbol_table: HashMap<String, ContextItem>,
    // Unit to Symbol name
    units: HashMap<Unit, String>,
    // Used to define new units
    next_unit: Unit,
    conversion_table: ConversionTable,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
            units: HashMap::new(),
            next_unit: 1,
            conversion_table: ConversionTable::new(),
        }
    }

    /// Defines a reasonble set of default built_in methods
    pub fn defaults() -> EvalContext {
        let mut context = EvalContext::new();

        context.set_constant("PREFIX", Fixity::Prefix.to_string());
        context.set_constant("INFIX", Fixity::Infix.to_string());
        context.set_constant("POSTFIX", Fixity::Postfix.to_string());

        context.define_built_in_method_defaults(
            "operator",
            4,
            BuiltInFunction::new(default_functions::operator),
        );

        context.define_built_in_method_defaults(
            "defineUnit",
            1,
            BuiltInFunction::new(default_functions::define_unit),
        );

        context.define_built_in_method_defaults(
            "convert",
            2,
            BuiltInFunction::new(default_functions::convert),
        );

        context.define_built_in_method_defaults(
            "unitFor",
            1,
            BuiltInFunction::new(default_functions::unit_for),
        );

        context.define_built_in_method_defaults(
            "valueOf",
            1,
            BuiltInFunction::new(default_functions::value_of),
        );

        context.define_built_in_method_defaults(
            "conversion",
            3,
            BuiltInFunction::new(default_functions::conversion),
        );

        context
    }

    /// Defines a context with all the defaults as well as definitions
    /// for common operators and units
    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::defaults();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        self.set(name, ContextItem::new_definition(fixity, precedence, function));
    }

    /// Defines a function in the context with defaults for precedence and fixity
    pub fn define_defaults(
        &mut self,
        name: &str,
        function: Function,
    ) {
        self.set(name, ContextItem::function_defaults(function));
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_built_in_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: BuiltInFunction,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Defines a built-in function in the context with defaults for precedence and fixity
    pub fn define_built_in_method_defaults(
        &mut self,
        name: &str,
        params: usize,
        function: BuiltInFunction,
    ) {
        self.set(name, ContextItem::built_in_defaults(function, params));
    }

    /// Creates a unique identifier for the given unit name
    /// Calling this more than once for the same unit name will end up
    /// with some duplicate definitons, should not be a huge deal but may
    /// lead to problems later on
    pub fn create_unit(&mut self, name: &str) -> Unit {
        let unit = self.next_unit;
        self.next_unit += 1;

        self.units.insert(unit, name.to_owned());

        unit
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    /// Removes a name from the context, does nothing if name is not there
    pub fn remove(&mut self, name: &str) {
        self.symbol_table.remove(name);
    }

    /// Converts the value to the given unit by doing appropriate
    /// transformations as prescribed by the conversion table
    /// Returns Err if no appropriate conversion is found
    pub fn convert(&mut self, value: RichNumber, unit: Option<Unit>) -> EvalResult {
        if value.unit.is_none() || unit.is_none() {
            Ok(ContextItem::Number(RichNumber::new(value.value, unit)))
        }
        else {
            let start = value.unit.unwrap();
            let unit = unit.unwrap();

            let conversions = self.conversion_table.conversion_steps(start, unit);

            if conversions.is_none() {
                Err(EvalError::ConversionUndefined {
                    start: start,
                    target: unit,
                })
            }
            else {
                let conversions = conversions.unwrap();

                let mut current = ContextItem::Number(value);
                for next_unit in conversions {
                    //TODO: unwrap_number() here may not be completely safe
                    //TODO: because it is dependent on the result of applying the converter
                    let current_number = current.unwrap_number();

                    // unwrap() is safe here because we used conversion_steps
                    let converter = self.conversion_table.get_converter(
                        current_number.unit.unwrap(),
                        next_unit
                    ).unwrap();

                    current = try!(self.apply_function(&converter, vec![
                        ContextItem::Number(current_number.without_units()),
                    ]));
                }

                debug_assert!({
                    let c = current.clone().unwrap_number().unit;
                    !c.is_none() && c.unwrap() == unit
                });

                Ok(current)
            }
        }
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define_defaults(&name, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        self.reduce(root)
    }

    fn reduce(&mut self, node: EvalTreeNode) -> EvalResult {
        let EvalTreeNode {
            item,
            children,
        } = node;

        let mut params = Vec::new();
        for child in children {
            params.push(try!(self.reduce(child)));
        }

        // Special case: when no parameters are provided, return
        // the function itself.
        // Added to support (f) and anonymous syntax
        if item.is_function() && params.is_empty() {
            return Ok(item.clone())
        }

        match item {
            ContextItem::BuiltInMethod { ref function, params: ref pn, .. } => {
                debug_assert!(!params.is_empty());

                debug_assert!(*pn != 0,
                    "Functions cannot have zero parameters");

                function.call(self, params)
            },
            ContextItem::Definition { ref function, .. } => {
                debug_assert!(!params.is_empty());
                self.apply_function(function, params)
            },
            otherwise => Ok(otherwise),
        }
    }

    /// Applies the given parameters to the given function
    fn apply_function(&mut self, function: &Function, params: Vec<ContextItem>) -> EvalResult {
        let param_names = &function.params;
        if params.len() != param_names.len() {
            return Err(EvalError::ExpectedParams(param_names.len()));
        }

        // need to munge parameter names
        // one day this will be replaced with a true stack
        // using characters that couldn't possibly be in any other symbol
        let munge = format!("[[{}]]", random::<u64>());

        let reserved_names = param_names.iter()
            .map(|n| (n.clone(), format!("{}{}", munge, n)))
            .collect::<HashMap<String, String>>();

        let body: Expr = self.munge_expr(&function.body, &reserved_names);

        // Temporarily add names
        for (i, name) in param_names.iter().enumerate() {
            let reserve = reserved_names.get(name).unwrap();
            self.set(reserve, params[i].clone());
        }

        let result = self.evaluate(body);

        for name in param_names {
            let reserve = reserved_names.get(name).unwrap();
            self.remove(reserve);
        }

        result
    }

    fn munge_expr(&self, expr: &Expr, reserved_names: &HashMap<String, String>) -> Expr {
        expr.iter().map(|x| {
            if let ExprItem::SingleTerm(Term::Symbol(ref name)) = *x {
                if reserved_names.contains_key(name) {
                    let new_name = reserved_names.get(name).unwrap().clone();
                    ExprItem::SingleTerm(Term::Symbol(new_name))
                }
                else {
                    x.clone()
                }
            }
            else {
                x.clone()
            }
        }).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use api::parse;

    use ast::*;
    use math::rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::prelude();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<|endoftext|>


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

// This test case tests the incremental compilation hash (ICH) implementation
// for match expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Add Arm ---------------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        2 => 2,
        _ => 100,
    }
}

// Change Order Of Arms --------------------------------------------------------
#[cfg(cfail1)]
pub fn change_order_of_arms(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_order_of_arms(x: u32) -> u32 {
    match x {
        1 => 1,
        0 => 0,
        _ => 100,
    }
}

// Add Guard Clause ------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if y => 1,
        _ => 100,
    }
}

// Change Guard Clause ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if y => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if !y => 1,
        _ => 100,
    }
}

// Add @-Binding ---------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => x,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        x @ _ => x,
    }
}

// Change Name of @-Binding ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_name_of_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        x @ _ => 7,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_name_of_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        y @ _ => 7,
    }
}

// Change Simple Binding To Pattern --------------------------------------------
#[cfg(cfail1)]
pub fn change_simple_name_to_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (0, 0) => 0,
        a => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_simple_name_to_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (0, 0) => 0,
        (x, y) => 1,
    }
}

// Change Name In Pattern ------------------------------------------------------
#[cfg(cfail1)]
pub fn change_name_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        (a, 1) => a,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_name_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (b, 0) => 0,
        (a, 1) => a,
        _ => 100,
    }
}

// Change Mutability Of Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (mut a, 0) => 0,
        _ => 1,
    }
}

// Add `ref` To Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (ref a, 0) => 0,
        _ => 1,
    }
}

// Add `&` To Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
    match (&x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
    match (&x, x & 1) {
        (&a, 0) => 0,
        _ => 1,
    }
}

// Change RHS Of Arm -----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_rhs_of_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 2,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_rhs_of_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 3,
        _ => 2,
    }
}

// Add Alternative To Arm ------------------------------------------------------
#[cfg(cfail1)]
pub fn add_alternative_to_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 2,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_alternative_to_arm(x: u32) -> u32 {
    match x {
        0 | 7 => 0,
        1 => 3,
        _ => 2,
    }
}
<commit_msg>tidy fixes<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This test case tests the incremental compilation hash (ICH) implementation
// for match expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Add Arm ---------------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        2 => 2,
        _ => 100,
    }
}

// Change Order Of Arms --------------------------------------------------------
#[cfg(cfail1)]
pub fn change_order_of_arms(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_order_of_arms(x: u32) -> u32 {
    match x {
        1 => 1,
        0 => 0,
        _ => 100,
    }
}

// Add Guard Clause ------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if y => 1,
        _ => 100,
    }
}

// Change Guard Clause ------------------------------------------------------------
#[cfg(cfail1)]
pub fn change_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if y => 1,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_guard_clause(x: u32, y: bool) -> u32 {
    match x {
        0 => 0,
        1 if !y => 1,
        _ => 100,
    }
}

// Add @-Binding ---------------------------------------------------------------
#[cfg(cfail1)]
pub fn add_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => x,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        x @ _ => x,
    }
}

// Change Name of @-Binding ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_name_of_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        x @ _ => 7,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_name_of_at_binding(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        y @ _ => 7,
    }
}

// Change Simple Binding To Pattern --------------------------------------------
#[cfg(cfail1)]
pub fn change_simple_name_to_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (0, 0) => 0,
        a => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_simple_name_to_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (0, 0) => 0,
        (x, y) => 1,
    }
}

// Change Name In Pattern ------------------------------------------------------
#[cfg(cfail1)]
pub fn change_name_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        (a, 1) => a,
        _ => 100,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_name_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (b, 0) => 0,
        (a, 1) => a,
        _ => 100,
    }
}

// Change Mutability Of Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (mut a, 0) => 0,
        _ => 1,
    }
}

// Add `ref` To Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
    match (x, x & 1) {
        (ref a, 0) => 0,
        _ => 1,
    }
}

// Add `&` To Binding In Pattern -------------------------------------
#[cfg(cfail1)]
pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
    match (&x, x & 1) {
        (a, 0) => 0,
        _ => 1,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
    match (&x, x & 1) {
        (&a, 0) => 0,
        _ => 1,
    }
}

// Change RHS Of Arm -----------------------------------------------------------
#[cfg(cfail1)]
pub fn change_rhs_of_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 2,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_rhs_of_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 3,
        _ => 2,
    }
}

// Add Alternative To Arm ------------------------------------------------------
#[cfg(cfail1)]
pub fn add_alternative_to_arm(x: u32) -> u32 {
    match x {
        0 => 0,
        1 => 1,
        _ => 2,
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2",
except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_alternative_to_arm(x: u32) -> u32 {
    match x {
        0 | 7 => 0,
        1 => 3,
        _ => 2,
    }
}
<|endoftext|>


<commit_before>// Generic AArch64 target for bare-metal code
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy};

pub fn target() -> Result<Target, String> {
    let opts = TargetOptions {
        linker: Some("rust-lld".to_owned()),
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        linker_is_gnu: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        abi_blacklist: super::arm_base::abi_blacklist(),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: opts,
    })
}
<commit_msg>targets: aarch64-unknown-none: Add +strict-align<commit_after>// Generic AArch64 target for bare-metal code
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy};

pub fn target() -> Result<Target, String> {
    let opts = TargetOptions {
        linker: Some("rust-lld".to_owned()),
        features: "+strict-align".to_string(),
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        linker_is_gnu: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        abi_blacklist: super::arm_base::abi_blacklist(),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: opts,
    })
}
<|endoftext|>