<commit_before>use {SystrayEvent, SystrayError, Callback, make_callback};
use std;
use std::cell::RefCell;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
use std::thread;
use std::collections::HashMap;
use winapi;
use user32;
use kernel32;
use shell32;
use winapi::windef::{HWND, HMENU, HICON, HBRUSH, HBITMAP};
use winapi::winnt::{LPCWSTR};
use winapi::minwindef::{UINT, DWORD, WPARAM, LPARAM, LRESULT, HINSTANCE};
use winapi::winuser::{WNDCLASSW, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT};

fn to_wstring(str : &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect::<Vec<_>>()
}

// Got this idea from glutin. Yay open source! Boo stupid winproc! Even more boo
// doing SetLongPtr tho.
thread_local!(static WININFO_STASH: RefCell<Option<WindowsLoopData>> = RefCell::new(None));

#[derive(Clone)]
struct WindowInfo {
    pub hwnd: HWND,
    pub hinstance: HINSTANCE,
    pub hmenu: HMENU,
}

unsafe impl Send for WindowInfo {}
unsafe impl Sync for WindowInfo {}

#[derive(Clone)]
struct WindowsLoopData {
    pub info: WindowInfo,
    pub tx: Sender<SystrayEvent>
}

unsafe extern "system" fn window_proc(h_wnd :HWND,
	                                    msg :UINT,
                                      w_param :WPARAM,
                                      l_param :LPARAM) -> LRESULT
{
    if msg == winapi::winuser::WM_MENUCOMMAND {
        WININFO_STASH.with(|stash| {
            let stash = stash.borrow();
            let stash = stash.as_ref();
            if let Some(stash) = stash {
                let menu_id = user32::GetMenuItemID(stash.info.hmenu,
                                                    w_param as i32) as i32;
                if menu_id != -1 {
                    stash.tx.send(SystrayEvent {
                        menu_index: menu_id as u32,
                        menu_checked: false
                    }).ok();
                }
            }
        });
    }

    if msg == winapi::winuser::WM_USER + 1 {
        if l_param as UINT == winapi::winuser::WM_LBUTTONUP ||
            l_param as UINT == winapi::winuser::WM_RBUTTONUP {
                let mut p = winapi::POINT {
                    x: 0,
                    y: 0
                };
                if user32::GetCursorPos(&mut p as *mut winapi::POINT) == 0 {
                    return 1;
                }
                user32::SetForegroundWindow(h_wnd);
                WININFO_STASH.with(|stash| {
                    let stash = stash.borrow();
                    let stash = stash.as_ref();
                    if let Some(stash) = stash {
                        user32::TrackPopupMenu(stash.info.hmenu,
                                               0,
                                               p.x,
                                               p.y,
                                               (winapi::TPM_BOTTOMALIGN | winapi::TPM_LEFTALIGN) as i32,
                                               h_wnd,
                                               std::ptr::null_mut());
                    }
                });
            }
    }
    if msg == winapi::winuser::WM_DESTROY {
        user32::PostQuitMessage(0);
    }
    return user32::DefWindowProcW(h_wnd, msg, w_param, l_param);
}
// Would be nice to have default for the notify icon struct, since there's a lot
// of setup code otherwise. To get around orphan trait error, define trait here.
trait Default {
    fn default() -> Self;
}

impl Default for winapi::shellapi::NOTIFYICONDATAA {
    fn default() -> winapi::shellapi::NOTIFYICONDATAA {
        winapi::shellapi::NOTIFYICONDATAA {
            cbSize: std::mem::size_of::<winapi::shellapi::NOTIFYICONDATAA>() as DWORD,
            hWnd: 0 as HWND,
            uID: 0x1 as UINT,
            uFlags: 0 as UINT,
            uCallbackMessage: 0 as UINT,
            hIcon: 0 as HICON,
            szTip: [0 as i8; 128],
            dwState: 0 as DWORD,
            dwStateMask: 0 as DWORD,
            szInfo: [0 as i8; 256],
            uTimeout: 0 as UINT,
            szInfoTitle: [0 as i8; 64],
            dwInfoFlags: 0 as UINT,
            guidItem: winapi::GUID {
                Data1: 0 as winapi::c_ulong,
                Data2: 0 as winapi::c_ushort,
                Data3: 0 as winapi::c_ushort,
                Data4: [0; 8]
            },
            hBalloonIcon: 0 as HICON
        }
    }
}

unsafe fn init_window() -> Result<WindowInfo, SystrayError> {
    let class_name = to_wstring("my_window");
    let hinstance : HINSTANCE = kernel32::GetModuleHandleA(std::ptr::null_mut());
    let wnd = WNDCLASSW {
        style: 0,
        lpfnWndProc: Some(window_proc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: 0 as HINSTANCE,
        hIcon: user32::LoadIconW(0 as HINSTANCE,
                                 winapi::winuser::IDI_APPLICATION),
        hCursor: user32::LoadCursorW(0 as HINSTANCE,
                                     winapi::winuser::IDI_APPLICATION),
        hbrBackground: 16 as HBRUSH,
        lpszMenuName: 0 as LPCWSTR,
        lpszClassName: class_name.as_ptr(),
    };
    user32::RegisterClassW(&wnd);
    let hwnd = user32::CreateWindowExW(0,
                                       class_name.as_ptr(),
                                       to_wstring("rust_systray_window").as_ptr(),
                                       WS_OVERLAPPEDWINDOW,
                                       CW_USEDEFAULT,
                                       0,
                                       CW_USEDEFAULT,
                                       0,
                                       0 as HWND,
                                       0 as HMENU,
                                       0 as HINSTANCE,
                                       std::ptr::null_mut());
    println!("Got window! {:?}", hwnd as u32);
    println!("Error? {}", kernel32::GetLastError());
    let mut nid = winapi::shellapi::NOTIFYICONDATAA::default();
    nid.hWnd = hwnd;
    nid.uID = 0x1;
    nid.uFlags = winapi::NIF_MESSAGE;
    nid.uCallbackMessage = winapi::WM_USER + 1;
    println!("Adding icon! {}", shell32::Shell_NotifyIconA(winapi::NIM_ADD,
                                                           &mut nid as *mut winapi::shellapi::NOTIFYICONDATAA));
    // Setup menu
    let hmenu = user32::CreatePopupMenu();
    let m = winapi::MENUINFO {
        cbSize: std::mem::size_of::<winapi::MENUINFO>() as DWORD,
        fMask: winapi::MIM_APPLYTOSUBMENUS | winapi::MIM_STYLE,
        dwStyle: winapi::MNS_NOTIFYBYPOS,
        cyMax: 0 as UINT,
        hbrBack: 0 as HBRUSH,
        dwContextHelpID: 0 as DWORD,
        dwMenuData: 0 as winapi::ULONG_PTR
    };
    println!("Created menu! {}", user32::SetMenuInfo(hmenu, &m as *const winapi::MENUINFO));

    Ok(WindowInfo {
        hwnd: hwnd,
        hmenu: hmenu,
        hinstance: hinstance,
    })
}

unsafe fn run_loop() {
    // Run message loop
    let mut msg = winapi::winuser::MSG {
        hwnd: 0 as HWND,
        message: 0 as UINT,
        wParam: 0 as WPARAM,
        lParam: 0 as LPARAM,
        time: 0 as DWORD,
        pt: winapi::windef::POINT { x: 0, y: 0, },
    };
    loop {
        println!("RUNNING LOOP");
        user32::GetMessageW(&mut msg, 0 as HWND, 0, 0);
        if msg.message == winapi::winuser::WM_QUIT {
            println!("QUITTING LOOP");
            break;
        }
        println!("{}", msg.message);
        user32::TranslateMessage(&mut msg);
        user32::DispatchMessageW(&mut msg);
    }
}

pub struct Window {
    info: WindowInfo,
    windows_loop: Option<thread::JoinHandle<()>>,
    menu_idx: u32,
    pub callback: HashMap<u32, Callback>,
    pub rx: Receiver<SystrayEvent>,
}

impl Window {
    pub fn new() -> Result<Window, SystrayError> {
        let (tx, rx) = channel();
        let (event_tx, event_rx) = channel();
        let windows_loop = thread::spawn(move || {
            unsafe {
                let i = init_window();
                let k;
                match i {
                    Ok(j) => {
                        tx.send(Ok(j.clone())).ok();
                        k = j;
                    }
                    Err(e) => {
                        // If creation didn't work, return out of the thread.
                        tx.send(Err(e)).ok();
                        return;
                    }
                };
                WININFO_STASH.with(|stash| {
                    let data = WindowsLoopData {
                        info: k,
                        tx: event_tx
                    };
                    (*stash.borrow_mut()) = Some(data);
                });
                run_loop();
            }
        });
        let info = match rx.recv().unwrap() {
            Ok(i) => i,
            Err(e) => {
                panic!(e);
            }
        };
        let mut w = Window {
            info: info,
            windows_loop: Some(windows_loop),
            rx: event_rx,
            menu_idx: 0,
            callback: HashMap::new()
        };
        // TODO This really shouldn't be compulsory. Need to figure out how to
        // make closures that can wrap around window object and know it.
        w.add_menu_entry(&"Quit".to_string());
        w.add_menu_separator();
        Ok(w)
    }

    pub fn quit(&mut self) {
        unsafe {
            user32::PostMessageW(self.info.hwnd, winapi::WM_DESTROY,
                                 0 as WPARAM, 0 as LPARAM);
        }
        if let Some(t) = self.windows_loop.take() {
            t.join().ok();
        }
    }

    pub fn set_tooltip(&self, tooltip: &String) {
        // Add Tooltip
        // Gross way to convert String to [i8; 128]
        // TODO: Clean up conversion, test for length so we don't panic at runtime
        let tt = tooltip.as_bytes().clone();
        let mut nid = winapi::shellapi::NOTIFYICONDATAA::default();
        nid.hWnd = self.info.hwnd;
        for i in 0..tt.len() {
            nid.szTip[i] = tt[i] as i8;
        }
        nid.uFlags = winapi::NIF_TIP;
        unsafe {
            println!("Setting tip! {}", shell32::Shell_NotifyIconA(winapi::NIM_MODIFY,
                                                                   &mut nid as *mut winapi::shellapi::NOTIFYICONDATAA));
        }
    }

    fn add_menu_entry(&mut self, item_name: &String) {
        let mut st = to_wstring(item_name);
        let idx = self.menu_idx;
        self.menu_idx += 1;
        let item = winapi::MENUITEMINFOW {
            cbSize: std::mem::size_of::<winapi::MENUITEMINFOW>() as UINT,
            fMask: (winapi::MIIM_FTYPE | winapi::MIIM_STRING | winapi::MIIM_ID | winapi::MIIM_STATE),
            fType: winapi::MFT_STRING,
            fState: 0 as UINT,
            wID: idx as UINT,
            hSubMenu: 0 as HMENU,
            hbmpChecked: 0 as HBITMAP,
            hbmpUnchecked: 0 as HBITMAP,
            dwItemData: 0 as winapi::ULONG_PTR,
            dwTypeData: st.as_mut_ptr(),
            cch: (item_name.len() * 2) as u32, // 16 bit characters
            hbmpItem: 0 as HBITMAP
        };
        unsafe {
            user32::InsertMenuItemW(self.info.hmenu, 0, 1, &item as *const winapi::MENUITEMINFOW);
        }
    }

    pub fn add_menu_separator(&mut self) {
        let idx = self.menu_idx;
        self.menu_idx += 1;
        let item = winapi::MENUITEMINFOW {
            cbSize: std::mem::size_of::<winapi::MENUITEMINFOW>() as UINT,
            fMask: winapi::MIIM_FTYPE,
            fType: winapi::MFT_SEPARATOR,
            fState: 0 as UINT,
            wID: idx as UINT,
            hSubMenu: 0 as HMENU,
            hbmpChecked: 0 as HBITMAP,
            hbmpUnchecked: 0 as HBITMAP,
            dwItemData: 0 as winapi::ULONG_PTR,
            dwTypeData: std::ptr::null_mut(),
            cch: 0 as u32, // 16 bit characters
            hbmpItem: 0 as HBITMAP
        };
        unsafe {
            user32::InsertMenuItemW(self.info.hmenu, 0, 1, &item as *const winapi::MENUITEMINFOW);
        }
    }

    pub fn add_menu_item<F>(&mut self, item_name: &String, f: F)
        where F: std::ops::Fn<(),Output=()> + 'static {
        let mut st = to_wstring(item_name);
        let idx = self.menu_idx;
        self.menu_idx += 1;
        let item = winapi::MENUITEMINFOW {
            cbSize: std::mem::size_of::<winapi::MENUITEMINFOW>() as UINT,
            fMask: (winapi::MIIM_FTYPE | winapi::MIIM_STRING | winapi::MIIM_ID | winapi::MIIM_STATE),
            fType: winapi::MFT_STRING,
            fState: 0 as UINT,
            wID: idx as UINT,
            hSubMenu: 0 as HMENU,
            hbmpChecked: 0 as HBITMAP,
            hbmpUnchecked: 0 as HBITMAP,
            dwItemData: 0 as winapi::ULONG_PTR,
            dwTypeData: st.as_mut_ptr(),
            cch: (item_name.len() * 2) as u32, // 16 bit characters
            hbmpItem: 0 as HBITMAP
        };
        unsafe {
            user32::InsertMenuItemW(self.info.hmenu, 0, 1, &item as *const winapi::MENUITEMINFOW);
        }
        self.callback.insert(idx, make_callback(f));
    }

    fn set_icon(&self, icon: HICON) {
        unsafe {
            let mut nid = winapi::shellapi::NOTIFYICONDATAA::default();
            nid.hWnd = self.info.hwnd;
            nid.uFlags = winapi::NIF_ICON;
            nid.hIcon = icon;
            println!("Setting icon! {}", shell32::Shell_NotifyIconA(winapi::NIM_MODIFY,
                                                                    &mut nid as *mut winapi::shellapi::NOTIFYICONDATAA));
        }
    }

    pub fn wait_for_message(&mut self) {
        loop {
            let msg = self.rx.recv().unwrap();
            println!("Got {}", msg.menu_index);
            if msg.menu_index == 0 {
                self.quit();
                return;
            }
            if self.callback.contains_key(&msg.menu_index) {
                self.callback.get(&msg.menu_index).map(|fun| fun());
            }
        }
    }

    pub fn set_icon_from_resource(&self, resource_name: &String) {
        let icon;
        unsafe {
            icon = user32::LoadImageW(self.info.hinstance,
                                      to_wstring(&resource_name).as_ptr(),
                                      winapi::IMAGE_ICON,
                                      64,
                                      64,
                                      0) as HICON;
        }
        self.set_icon(icon);
    }

    pub fn set_icon_from_file(&self, icon_file: &String) {
        let wstr_icon_file = to_wstring(&icon_file);
        let hicon;
        unsafe {
            hicon = user32::LoadImageW(std::ptr::null_mut() as HINSTANCE, wstr_icon_file.as_ptr(),
                                       winapi::IMAGE_ICON, 64, 64, winapi::LR_LOADFROMFILE) as HICON;
        }
        if hicon == std::ptr::null_mut() as HICON {
            // TODO Throw Error
            return;
        }
        self.set_icon(hicon);
    }
}
<commit_msg>chore: Clean up icon/menu item struct creation<commit_after>use {SystrayEvent, SystrayError, Callback, make_callback};
use std;
use std::cell::RefCell;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
use std::thread;
use std::collections::HashMap;
use winapi;
use user32;
use kernel32;
use shell32;
use winapi::windef::{HWND, HMENU, HICON, HBRUSH, HBITMAP};
use winapi::winnt::{LPCWSTR};
use winapi::minwindef::{UINT, DWORD, WPARAM, LPARAM, LRESULT, HINSTANCE};
use winapi::winuser::{WNDCLASSW, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT};

fn to_wstring(str : &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect::<Vec<_>>()
}

// Got this idea from glutin. Yay open source! Boo stupid winproc! Even more boo
// doing SetLongPtr tho.
thread_local!(static WININFO_STASH: RefCell<Option<WindowsLoopData>> = RefCell::new(None));

#[derive(Clone)]
struct WindowInfo {
    pub hwnd: HWND,
    pub hinstance: HINSTANCE,
    pub hmenu: HMENU,
}

unsafe impl Send for WindowInfo {}
unsafe impl Sync for WindowInfo {}

#[derive(Clone)]
struct WindowsLoopData {
    pub info: WindowInfo,
    pub tx: Sender<SystrayEvent>
}

unsafe extern "system" fn window_proc(h_wnd :HWND,
	                                    msg :UINT,
                                      w_param :WPARAM,
                                      l_param :LPARAM) -> LRESULT
{
    if msg == winapi::winuser::WM_MENUCOMMAND {
        WININFO_STASH.with(|stash| {
            let stash = stash.borrow();
            let stash = stash.as_ref();
            if let Some(stash) = stash {
                let menu_id = user32::GetMenuItemID(stash.info.hmenu,
                                                    w_param as i32) as i32;
                if menu_id != -1 {
                    stash.tx.send(SystrayEvent {
                        menu_index: menu_id as u32,
                        menu_checked: false
                    }).ok();
                }
            }
        });
    }

    if msg == winapi::winuser::WM_USER + 1 {
        if l_param as UINT == winapi::winuser::WM_LBUTTONUP ||
            l_param as UINT == winapi::winuser::WM_RBUTTONUP {
                let mut p = winapi::POINT {
                    x: 0,
                    y: 0
                };
                if user32::GetCursorPos(&mut p as *mut winapi::POINT) == 0 {
                    return 1;
                }
                user32::SetForegroundWindow(h_wnd);
                WININFO_STASH.with(|stash| {
                    let stash = stash.borrow();
                    let stash = stash.as_ref();
                    if let Some(stash) = stash {
                        user32::TrackPopupMenu(stash.info.hmenu,
                                               0,
                                               p.x,
                                               p.y,
                                               (winapi::TPM_BOTTOMALIGN | winapi::TPM_LEFTALIGN) as i32,
                                               h_wnd,
                                               std::ptr::null_mut());
                    }
                });
            }
    }
    if msg == winapi::winuser::WM_DESTROY {
        user32::PostQuitMessage(0);
    }
    return user32::DefWindowProcW(h_wnd, msg, w_param, l_param);
}

fn get_nid_struct(hwnd : &HWND) -> winapi::shellapi::NOTIFYICONDATAW {
    winapi::shellapi::NOTIFYICONDATAW {
        cbSize: std::mem::size_of::<winapi::shellapi::NOTIFYICONDATAW>() as DWORD,
        hWnd: *hwnd,
        uID: 0x1 as UINT,
        uFlags: 0 as UINT,
        uCallbackMessage: 0 as UINT,
        hIcon: 0 as HICON,
        szTip: [0 as u16; 128],
        dwState: 0 as DWORD,
        dwStateMask: 0 as DWORD,
        szInfo: [0 as u16; 256],
        uTimeout: 0 as UINT,
        szInfoTitle: [0 as u16; 64],
        dwInfoFlags: 0 as UINT,
        guidItem: winapi::GUID {
            Data1: 0 as winapi::c_ulong,
            Data2: 0 as winapi::c_ushort,
            Data3: 0 as winapi::c_ushort,
            Data4: [0; 8]
        },
        hBalloonIcon: 0 as HICON
    }
}

fn get_menu_item_struct() -> winapi::MENUITEMINFOW {
    winapi::MENUITEMINFOW {
        cbSize: std::mem::size_of::<winapi::MENUITEMINFOW>() as UINT,
        fMask: 0 as UINT,
        fType: 0 as UINT,
        fState: 0 as UINT,
        wID: 0 as UINT,
        hSubMenu: 0 as HMENU,
        hbmpChecked: 0 as HBITMAP,
        hbmpUnchecked: 0 as HBITMAP,
        dwItemData: 0 as winapi::ULONG_PTR,
        dwTypeData: std::ptr::null_mut(),
        cch: 0 as u32,
        hbmpItem: 0 as HBITMAP
    }

}

unsafe fn init_window() -> Result<WindowInfo, SystrayError> {
    let class_name = to_wstring("my_window");
    let hinstance : HINSTANCE = kernel32::GetModuleHandleA(std::ptr::null_mut());
    let wnd = WNDCLASSW {
        style: 0,
        lpfnWndProc: Some(window_proc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: 0 as HINSTANCE,
        hIcon: user32::LoadIconW(0 as HINSTANCE,
                                 winapi::winuser::IDI_APPLICATION),
        hCursor: user32::LoadCursorW(0 as HINSTANCE,
                                     winapi::winuser::IDI_APPLICATION),
        hbrBackground: 16 as HBRUSH,
        lpszMenuName: 0 as LPCWSTR,
        lpszClassName: class_name.as_ptr(),
    };
    user32::RegisterClassW(&wnd);
    let hwnd = user32::CreateWindowExW(0,
                                       class_name.as_ptr(),
                                       to_wstring("rust_systray_window").as_ptr(),
                                       WS_OVERLAPPEDWINDOW,
                                       CW_USEDEFAULT,
                                       0,
                                       CW_USEDEFAULT,
                                       0,
                                       0 as HWND,
                                       0 as HMENU,
                                       0 as HINSTANCE,
                                       std::ptr::null_mut());
    println!("Got window! {:?}", hwnd as u32);
    println!("Error? {}", kernel32::GetLastError());
    let mut nid = get_nid_struct(&hwnd);
    nid.uID = 0x1;
    nid.uFlags = winapi::NIF_MESSAGE;
    nid.uCallbackMessage = winapi::WM_USER + 1;
    println!("Adding icon! {}", shell32::Shell_NotifyIconW(winapi::NIM_ADD,
                                                           &mut nid as *mut winapi::shellapi::NOTIFYICONDATAW));
    // Setup menu
    let hmenu = user32::CreatePopupMenu();
    let m = winapi::MENUINFO {
        cbSize: std::mem::size_of::<winapi::MENUINFO>() as DWORD,
        fMask: winapi::MIM_APPLYTOSUBMENUS | winapi::MIM_STYLE,
        dwStyle: winapi::MNS_NOTIFYBYPOS,
        cyMax: 0 as UINT,
        hbrBack: 0 as HBRUSH,
        dwContextHelpID: 0 as DWORD,
        dwMenuData: 0 as winapi::ULONG_PTR
    };
    println!("Created menu! {}", user32::SetMenuInfo(hmenu, &m as *const winapi::MENUINFO));

    Ok(WindowInfo {
        hwnd: hwnd,
        hmenu: hmenu,
        hinstance: hinstance,
    })
}

unsafe fn run_loop() {
    // Run message loop
    let mut msg = winapi::winuser::MSG {
        hwnd: 0 as HWND,
        message: 0 as UINT,
        wParam: 0 as WPARAM,
        lParam: 0 as LPARAM,
        time: 0 as DWORD,
        pt: winapi::windef::POINT { x: 0, y: 0, },
    };
    loop {
        println!("RUNNING LOOP");
        user32::GetMessageW(&mut msg, 0 as HWND, 0, 0);
        if msg.message == winapi::winuser::WM_QUIT {
            println!("QUITTING LOOP");
            break;
        }
        println!("{}", msg.message);
        user32::TranslateMessage(&mut msg);
        user32::DispatchMessageW(&mut msg);
    }
}

pub struct Window {
    info: WindowInfo,
    windows_loop: Option<thread::JoinHandle<()>>,
    menu_idx: u32,
    pub callback: HashMap<u32, Callback>,
    pub rx: Receiver<SystrayEvent>,
}

impl Window {
    pub fn new() -> Result<Window, SystrayError> {
        let (tx, rx) = channel();
        let (event_tx, event_rx) = channel();
        let windows_loop = thread::spawn(move || {
            unsafe {
                let i = init_window();
                let k;
                match i {
                    Ok(j) => {
                        tx.send(Ok(j.clone())).ok();
                        k = j;
                    }
                    Err(e) => {
                        // If creation didn't work, return out of the thread.
                        tx.send(Err(e)).ok();
                        return;
                    }
                };
                WININFO_STASH.with(|stash| {
                    let data = WindowsLoopData {
                        info: k,
                        tx: event_tx
                    };
                    (*stash.borrow_mut()) = Some(data);
                });
                run_loop();
            }
        });
        let info = match rx.recv().unwrap() {
            Ok(i) => i,
            Err(e) => {
                panic!(e);
            }
        };
        let mut w = Window {
            info: info,
            windows_loop: Some(windows_loop),
            rx: event_rx,
            menu_idx: 0,
            callback: HashMap::new()
        };
        // TODO This really shouldn't be compulsory. Need to figure out how to
        // make closures that can wrap around window object and know it.
        w.add_menu_entry(&"Quit".to_string());
        w.add_menu_separator();
        Ok(w)
    }

    pub fn quit(&mut self) {
        unsafe {
            user32::PostMessageW(self.info.hwnd, winapi::WM_DESTROY,
                                 0 as WPARAM, 0 as LPARAM);
        }
        if let Some(t) = self.windows_loop.take() {
            t.join().ok();
        }
    }

    pub fn set_tooltip(&self, tooltip: &String) {
        // Add Tooltip
        // Gross way to convert String to [i8; 128]
        // TODO: Clean up conversion, test for length so we don't panic at runtime
        let tt = tooltip.as_bytes().clone();
        let mut nid = get_nid_struct(&self.info.hwnd);
        for i in 0..tt.len() {
            nid.szTip[i] = tt[i] as u16;
        }
        nid.uFlags = winapi::NIF_TIP;
        unsafe {
            println!("Setting tip! {}", shell32::Shell_NotifyIconW(winapi::NIM_MODIFY,
                                                                   &mut nid as *mut winapi::shellapi::NOTIFYICONDATAW));
        }
    }

    fn add_menu_entry(&mut self, item_name: &String) -> u32 {
        let mut st = to_wstring(item_name);
        let idx = self.menu_idx;
        self.menu_idx += 1;
        let mut item = get_menu_item_struct();
        item.fMask = winapi::MIIM_FTYPE | winapi::MIIM_STRING | winapi::MIIM_ID | winapi::MIIM_STATE;
        item.fType = winapi::MFT_STRING;
        item.wID = idx;
        item.dwTypeData = st.as_mut_ptr();
        item.cch = (item_name.len() * 2) as u32;
        unsafe {
            user32::InsertMenuItemW(self.info.hmenu, 0, 1, &item as *const winapi::MENUITEMINFOW);
        }
        idx
    }

    pub fn add_menu_separator(&mut self) {
        let idx = self.menu_idx;
        self.menu_idx += 1;
        let mut item = get_menu_item_struct();
        item.fMask = winapi::MIIM_FTYPE;
        item.fType = winapi::MFT_SEPARATOR;
        item.wID = idx;
        unsafe {
            user32::InsertMenuItemW(self.info.hmenu, 0, 1, &item as *const winapi::MENUITEMINFOW);
        }
    }

    pub fn add_menu_item<F>(&mut self, item_name: &String, f: F)
        where F: std::ops::Fn<(),Output=()> + 'static {
        let idx = self.add_menu_entry(item_name);
        self.callback.insert(idx, make_callback(f));
    }

    fn set_icon(&self, icon: HICON) {
        unsafe {
            let mut nid = get_nid_struct(&self.info.hwnd);
            nid.uFlags = winapi::NIF_ICON;
            nid.hIcon = icon;
            println!("Setting icon! {}", shell32::Shell_NotifyIconW(winapi::NIM_MODIFY,
                                                                    &mut nid as *mut winapi::shellapi::NOTIFYICONDATAW));
        }
    }

    pub fn wait_for_message(&mut self) {
        loop {
            let msg = self.rx.recv().unwrap();
            println!("Got {}", msg.menu_index);
            if msg.menu_index == 0 {
                self.quit();
                return;
            }
            if self.callback.contains_key(&msg.menu_index) {
                self.callback.get(&msg.menu_index).map(|fun| fun());
            }
        }
    }

    pub fn set_icon_from_resource(&self, resource_name: &String) {
        let icon;
        unsafe {
            icon = user32::LoadImageW(self.info.hinstance,
                                      to_wstring(&resource_name).as_ptr(),
                                      winapi::IMAGE_ICON,
                                      64,
                                      64,
                                      0) as HICON;
        }
        self.set_icon(icon);
    }

    pub fn set_icon_from_file(&self, icon_file: &String) {
        let wstr_icon_file = to_wstring(&icon_file);
        let hicon;
        unsafe {
            hicon = user32::LoadImageW(std::ptr::null_mut() as HINSTANCE, wstr_icon_file.as_ptr(),
                                       winapi::IMAGE_ICON, 64, 64, winapi::LR_LOADFROMFILE) as HICON;
        }
        if hicon == std::ptr::null_mut() as HICON {
            // TODO Throw Error
            return;
        }
        self.set_icon(hicon);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Result, Formatter, Display};
use TimeSpan;
use super::{Accuracy, TimeFormatter};

pub struct Inner {
    time: Option<TimeSpan>,
    accuracy: Accuracy,
}

pub struct PossibleTimeSave {
    accuracy: Accuracy,
}

impl PossibleTimeSave {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_accuracy(accuracy: Accuracy) -> Self {
        PossibleTimeSave { accuracy: accuracy }
    }
}

impl Default for PossibleTimeSave {
    fn default() -> Self {
        PossibleTimeSave { accuracy: Accuracy::Tenths }
    }
}

impl<'a> TimeFormatter<'a> for PossibleTimeSave {
    type Inner = Inner;

    fn format<T>(&self, time: T) -> Self::Inner
        where T: Into<Option<TimeSpan>>
    {
        Inner {
            time: time.into(),
            accuracy: self.accuracy,
        }
    }
}

impl Display for Inner {
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(time) = self.time {
            let mut total_seconds = time.total_seconds();
            if total_seconds < 0.0 {
                total_seconds *= -1.0;
                write!(f, "−")?;
            }
            let subseconds = total_seconds % 1.0;
            let total_seconds = total_seconds as u64;
            let seconds = total_seconds % 60;
            let total_minutes = total_seconds / 60;
            let minutes = total_minutes % 60;
            let hours = total_minutes / 60;
            if hours > 0 {
                write!(f, "{}:{:02}:{:02}", hours, minutes, seconds)
            } else if total_minutes > 0 {
                write!(f, "{}:{:02}", minutes, seconds)
            } else {
                write!(f, "{}", seconds)?;
                match self.accuracy {
                    Accuracy::Hundredths => write!(f, ".{:02}", (subseconds * 100.0) as u8),
                    Accuracy::Tenths => write!(f, ".{:01}", (subseconds * 10.0) as u8),
                    Accuracy::Seconds => Ok(()),
                }
            }
        } else {
            write!(f, "—")
        }
    }
}
<commit_msg>Corret formatting for Possible Time Save Component<commit_after>use std::fmt::{Result, Formatter, Display};
use TimeSpan;
use super::{Accuracy, TimeFormatter};

pub struct Inner {
    time: Option<TimeSpan>,
    accuracy: Accuracy,
}

pub struct PossibleTimeSave {
    accuracy: Accuracy,
}

impl PossibleTimeSave {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_accuracy(accuracy: Accuracy) -> Self {
        PossibleTimeSave { accuracy: accuracy }
    }
}

impl Default for PossibleTimeSave {
    fn default() -> Self {
        PossibleTimeSave { accuracy: Accuracy::Hundredths }
    }
}

impl<'a> TimeFormatter<'a> for PossibleTimeSave {
    type Inner = Inner;

    fn format<T>(&self, time: T) -> Self::Inner
        where T: Into<Option<TimeSpan>>
    {
        Inner {
            time: time.into(),
            accuracy: self.accuracy,
        }
    }
}

impl Display for Inner {
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(time) = self.time {
            let mut total_seconds = time.total_seconds();
            if total_seconds < 0.0 {
                total_seconds *= -1.0;
                write!(f, "−")?;
            }
            let subseconds = total_seconds % 1.0;
            let total_seconds = total_seconds as u64;
            let seconds = total_seconds % 60;
            let total_minutes = total_seconds / 60;
            let minutes = total_minutes % 60;
            let hours = total_minutes / 60;
            if hours > 0 {
                write!(f, "{}:{:02}:{:02}", hours, minutes, seconds)?;
            } else if total_minutes > 0 {
                write!(f, "{}:{:02}", minutes, seconds)?;
            } else {
                write!(f, "{}", seconds)?;
            }
            match self.accuracy {
                Accuracy::Hundredths => write!(f, ".{:02}", (subseconds * 100.0) as u8),
                Accuracy::Tenths => write!(f, ".{:01}", (subseconds * 10.0) as u8),
                Accuracy::Seconds => Ok(()),
            }
        } else {
            write!(f, "—")
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;

use petgraph::graph::NodeIndex;
use petgraph::{EdgeDirection, Graph};
use regex::Regex;

use lazy_static::lazy_static;
use octobuild::cluster::client::RemoteCompiler;
use octobuild::compiler::*;
use octobuild::config::Config;
use octobuild::simple::create_temp_dir;
use octobuild::simple::supported_compilers;
use octobuild::version;
use octobuild::worker::execute_graph;
use octobuild::worker::validate_graph;
use octobuild::worker::{BuildAction, BuildGraph, BuildResult, BuildTask};
use octobuild::xg;
use octobuild::xg::parser::{XgGraph, XgNode};

fn main() {
    println!("xgConsole ({}):", version::full_version());
    let args = Vec::from_iter(env::args());
    for arg in args.iter() {
        println!("  {}", arg);
    }
    if args.len() == 1 {
        println!();
        Config::help();
        return;
    }

    process::exit(match execute(&args[1..]) {
        Ok(result) => match result {
            Some(r) => r,
            None => 501,
        },
        Err(e) => {
            println!("FATAL ERROR: {}", e);
            500
        }
    })
}

fn is_flag(arg: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
    }
    RE.is_match(arg)
}

#[cfg(unix)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    files.push(Path::new(arg).to_path_buf());
    files
}

#[cfg(windows)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    use std::fs;

    fn mask_to_regex(mask: &str) -> Regex {
        let mut result = String::new();
        let mut begin = 0;
        result.push_str("^");
        for (index, separator) in mask.match_indices(|c| c == '?' || c == '*') {
            result.push_str(&regex::escape(&mask[begin..index]));
            result.push_str(match separator {
                "?" => ".",
                "*" => ".*",
                unknown => panic!("Unexpected separator: {}", unknown),
            });
            begin = index + separator.len()
        }
        result.push_str(&regex::escape(&mask[begin..]));
        result.push_str("$");
        Regex::new(&result).unwrap()
    }

    fn find_files(dir: &Path, mask: &str) -> Result<Vec<PathBuf>, Error> {
        let mut result = Vec::new();
        let expr = mask_to_regex(&mask.to_lowercase());
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            if entry
                .file_name()
                .to_str()
                .map_or(false, |s| expr.is_match(&s.to_lowercase()))
            {
                result.push(entry.path());
            }
        }
        Ok(result)
    }

    let path = Path::new(arg).to_path_buf();
    let mask = path.file_name().and_then(|name| name.to_str());
    match mask {
        Some(ref mask) if mask.contains(|c| c == '?' || c == '*') => {
            match find_files(path.parent().unwrap_or_else(|| Path::new(".")), mask) {
                Ok(ref mut found) if !found.is_empty() => {
                    files.append(found);
                }
                _ => {
                    files.push(path);
                }
            }
        }
        _ => {
            files.push(path);
        }
    }
    files
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
    let config = Config::new()?;
    let state = SharedState::new(&config)?;
    let compiler = RemoteCompiler::new(
        &config.coordinator,
        supported_compilers(&create_temp_dir()?),
    );
    let files = args
        .iter()
        .filter(|a| !is_flag(a))
        .fold(Vec::new(), |state, a| expand_files(state, &a));
    if files.is_empty() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "Build task files not found",
        ));
    }

    let mut graph = Graph::new();
    for arg in files.iter() {
        let file = File::open(&Path::new(arg))?;
        xg::parser::parse(&mut graph, BufReader::new(file))?;
    }
    let build_graph = validate_graph(graph).and_then(|graph| prepare_graph(&compiler, graph))?;

    let result = execute_graph(&state, build_graph, config.process_limit, print_task_result);
    let _ = state.cache.cleanup();
    println!("{}", state.statistic.to_string());
    result
}

fn env_resolver(name: &str) -> Option<String> {
    env::var(name).ok()
}

fn prepare_graph<C: Compiler>(compiler: &C, graph: XgGraph) -> Result<BuildGraph, Error> {
    let mut remap: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());
    let mut depends: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());

    let mut result: BuildGraph = Graph::new();
    for raw_node in graph.raw_nodes().iter() {
        let node: &XgNode = &raw_node.weight;
        let args: Vec<String> = node
            .args
            .iter()
            .map(|ref arg| expand_arg(&arg, &env_resolver))
            .collect();
        let command = node.command.clone();

        let actions = BuildAction::create_tasks(compiler, command.clone(), &args, &node.title);
        let node_index = NodeIndex::new(remap.len());
        if actions.len() == 1 {
            depends.push(node_index);
            remap.push(result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: actions.into_iter().next().unwrap(),
            })));
        } else {
            // Add group node for tracking end of all task actions
            let group_node = result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: BuildAction::Empty,
            }));
            depends.push(NodeIndex::end());
            // Add task actions
            let mut index = 1;
            let total = actions.len();
            for action in actions.into_iter() {
                let action_node = result.add_node(Arc::new(BuildTask {
                    title: format!("{} ({}/{})", node.title, index, total),
                    action,
                }));
                depends.push(node_index);
                result.add_edge(group_node, action_node, ());
                index += 1;
            }
            remap.push(group_node);
        }
    }

    assert!(remap.len() == graph.node_count());
    assert!(depends.len() == result.node_count());
    for i in 0..depends.len() {
        let node_a = NodeIndex::new(i);
        for neighbor in
            graph.neighbors_directed(depends.get(i).unwrap().clone(), EdgeDirection::Outgoing)
        {
            let node_b = remap.get(neighbor.index()).unwrap();
            result.add_edge(node_a, node_b.clone(), ());
        }
    }
    validate_graph(result)
}

fn print_task_result(result: BuildResult) -> Result<(), Error> {
    println!(
        "#{} {}/{}: {}",
        result.worker, result.completed, result.total, result.task.title
    );
    match result.result {
        Ok(ref output) => {
            io::stdout().write_all(&output.stdout)?;
            io::stderr().write_all(&output.stderr)?;
        }
        Err(_) => {}
    }
    Ok(())
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
    let mut result = String::new();
    let mut suffix = arg;
    loop {
        match suffix.find("$(") {
            Some(begin) => match suffix[begin..].find(')') {
                Some(end) => {
                    let name = &suffix[begin + 2..begin + end];
                    match resolver(name) {
                        Some(ref value) => {
                            result += &suffix[..begin];
                            result += &value;
                        }
                        None => {
                            result += &suffix[..=begin + end];
                        }
                    }
                    suffix = &suffix[begin + end + 1..];
                }
                None => {
                    result += suffix;
                    break;
                }
            },
            None => {
                result += suffix;
                break;
            }
        }
    }
    result
}

#[test]
fn test_parse_vars() {
    assert_eq!(
        expand_arg(
            "A$(test)$(inner)$(none)B",
            &|name: &str| -> Option<String> {
                match name {
                    "test" => Some("foo".to_string()),
                    "inner" => Some("$(bar)".to_string()),
                    "none" => None,
                    _ => {
                        assert!(false, format!("Unexpected value: {}", name));
                        None
                    }
                }
            },
        ),
        "Afoo$(bar)$(none)B"
    );
}

#[test]
fn test_is_flag() {
    assert_eq!(is_flag("/Wait"), true);
    assert_eq!(is_flag("/out=/foo/bar"), true);
    assert_eq!(is_flag("/out/foo/bar"), false);
    assert_eq!(is_flag("foo/bar"), false);
    assert_eq!(is_flag("/Wait.xml"), false);
    assert_eq!(is_flag("/Wait/foo=bar"), false);
    assert_eq!(is_flag("/WaitFoo=bar"), true);
    assert_eq!(is_flag("/Wait.Foo=bar"), false);
    assert_eq!(is_flag("/Wait=/foo/bar"), true);
}
<commit_msg>Clippy fix<commit_after>use std::env;
use std::fs::File;
use std::io;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;

use petgraph::graph::NodeIndex;
use petgraph::{EdgeDirection, Graph};
use regex::Regex;

use lazy_static::lazy_static;
use octobuild::cluster::client::RemoteCompiler;
use octobuild::compiler::*;
use octobuild::config::Config;
use octobuild::simple::create_temp_dir;
use octobuild::simple::supported_compilers;
use octobuild::version;
use octobuild::worker::execute_graph;
use octobuild::worker::validate_graph;
use octobuild::worker::{BuildAction, BuildGraph, BuildResult, BuildTask};
use octobuild::xg;
use octobuild::xg::parser::{XgGraph, XgNode};

fn main() {
    println!("xgConsole ({}):", version::full_version());
    let args = Vec::from_iter(env::args());
    for arg in args.iter() {
        println!("  {}", arg);
    }
    if args.len() == 1 {
        println!();
        Config::help();
        return;
    }

    process::exit(match execute(&args[1..]) {
        Ok(result) => match result {
            Some(r) => r,
            None => 501,
        },
        Err(e) => {
            println!("FATAL ERROR: {}", e);
            500
        }
    })
}

fn is_flag(arg: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
    }
    RE.is_match(arg)
}

#[cfg(unix)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    files.push(Path::new(arg).to_path_buf());
    files
}

#[cfg(windows)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    use std::fs;

    fn mask_to_regex(mask: &str) -> Regex {
        let mut result = String::new();
        let mut begin = 0;
        result.push_str("^");
        for (index, separator) in mask.match_indices(|c| c == '?' || c == '*') {
            result.push_str(&regex::escape(&mask[begin..index]));
            result.push_str(match separator {
                "?" => ".",
                "*" => ".*",
                unknown => panic!("Unexpected separator: {}", unknown),
            });
            begin = index + separator.len()
        }
        result.push_str(&regex::escape(&mask[begin..]));
        result.push_str("$");
        Regex::new(&result).unwrap()
    }

    fn find_files(dir: &Path, mask: &str) -> Result<Vec<PathBuf>, Error> {
        let mut result = Vec::new();
        let expr = mask_to_regex(&mask.to_lowercase());
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            if entry
                .file_name()
                .to_str()
                .map_or(false, |s| expr.is_match(&s.to_lowercase()))
            {
                result.push(entry.path());
            }
        }
        Ok(result)
    }

    let path = Path::new(arg).to_path_buf();
    let mask = path.file_name().and_then(|name| name.to_str());
    match mask {
        Some(ref mask) if mask.contains(|c| c == '?' || c == '*') => {
            match find_files(path.parent().unwrap_or_else(|| Path::new(".")), mask) {
                Ok(ref mut found) if !found.is_empty() => {
                    files.append(found);
                }
                _ => {
                    files.push(path);
                }
            }
        }
        _ => {
            files.push(path);
        }
    }
    files
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
    let config = Config::new()?;
    let state = SharedState::new(&config)?;
    let compiler = RemoteCompiler::new(
        &config.coordinator,
        supported_compilers(&create_temp_dir()?),
    );
    let files = args
        .iter()
        .filter(|a| !is_flag(a))
        .fold(Vec::new(), |state, a| expand_files(state, &a));
    if files.is_empty() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "Build task files not found",
        ));
    }

    let mut graph = Graph::new();
    for arg in files.iter() {
        let file = File::open(&Path::new(arg))?;
        xg::parser::parse(&mut graph, BufReader::new(file))?;
    }
    let build_graph = validate_graph(graph).and_then(|graph| prepare_graph(&compiler, graph))?;

    let result = execute_graph(&state, build_graph, config.process_limit, print_task_result);
    let _ = state.cache.cleanup();
    println!("{}", state.statistic.to_string());
    result
}

fn env_resolver(name: &str) -> Option<String> {
    env::var(name).ok()
}

fn prepare_graph<C: Compiler>(compiler: &C, graph: XgGraph) -> Result<BuildGraph, Error> {
    let mut remap: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());
    let mut depends: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());

    let mut result: BuildGraph = Graph::new();
    for raw_node in graph.raw_nodes().iter() {
        let node: &XgNode = &raw_node.weight;
        let args: Vec<String> = node
            .args
            .iter()
            .map(|ref arg| expand_arg(&arg, &env_resolver))
            .collect();
        let command = node.command.clone();

        let actions = BuildAction::create_tasks(compiler, command.clone(), &args, &node.title);
        let node_index = NodeIndex::new(remap.len());
        if actions.len() == 1 {
            depends.push(node_index);
            remap.push(result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: actions.into_iter().next().unwrap(),
            })));
        } else {
            // Add group node for tracking end of all task actions
            let group_node = result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: BuildAction::Empty,
            }));
            depends.push(NodeIndex::end());
            // Add task actions
            let mut index = 1;
            let total = actions.len();
            for action in actions.into_iter() {
                let action_node = result.add_node(Arc::new(BuildTask {
                    title: format!("{} ({}/{})", node.title, index, total),
                    action,
                }));
                depends.push(node_index);
                result.add_edge(group_node, action_node, ());
                index += 1;
            }
            remap.push(group_node);
        }
    }

    assert!(remap.len() == graph.node_count());
    assert!(depends.len() == result.node_count());
    for i in 0..depends.len() {
        let node_a = NodeIndex::new(i);
        for neighbor in
            graph.neighbors_directed(depends.get(i).unwrap().clone(), EdgeDirection::Outgoing)
        {
            let node_b = remap.get(neighbor.index()).unwrap();
            result.add_edge(node_a, node_b.clone(), ());
        }
    }
    validate_graph(result)
}

fn print_task_result(result: BuildResult) -> Result<(), Error> {
    println!(
        "#{} {}/{}: {}",
        result.worker, result.completed, result.total, result.task.title
    );
    match result.result {
        Ok(ref output) => {
            io::stdout().write_all(&output.stdout)?;
            io::stderr().write_all(&output.stderr)?;
        }
        Err(_) => {}
    }
    Ok(())
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
    let mut result = String::new();
    let mut suffix = arg;
    loop {
        match suffix.find("$(") {
            Some(begin) => match suffix[begin..].find(')') {
                Some(end) => {
                    let name = &suffix[begin + 2..begin + end];
                    match resolver(name) {
                        Some(ref value) => {
                            result += &suffix[..begin];
                            result += &value;
                        }
                        None => {
                            result += &suffix[..=begin + end];
                        }
                    }
                    suffix = &suffix[begin + end + 1..];
                }
                None => {
                    result += suffix;
                    break;
                }
            },
            None => {
                result += suffix;
                break;
            }
        }
    }
    result
}

#[test]
fn test_parse_vars() {
    assert_eq!(
        expand_arg(
            "A$(test)$(inner)$(none)B",
            &|name: &str| -> Option<String> {
                match name {
                    "test" => Some("foo".to_string()),
                    "inner" => Some("$(bar)".to_string()),
                    "none" => None,
                    _ => {
                        unreachable!(format!("Unexpected value: {}", name));
                    }
                }
            },
        ),
        "Afoo$(bar)$(none)B"
    );
}

#[test]
fn test_is_flag() {
    assert_eq!(is_flag("/Wait"), true);
    assert_eq!(is_flag("/out=/foo/bar"), true);
    assert_eq!(is_flag("/out/foo/bar"), false);
    assert_eq!(is_flag("foo/bar"), false);
    assert_eq!(is_flag("/Wait.xml"), false);
    assert_eq!(is_flag("/Wait/foo=bar"), false);
    assert_eq!(is_flag("/WaitFoo=bar"), true);
    assert_eq!(is_flag("/Wait.Foo=bar"), false);
    assert_eq!(is_flag("/Wait=/foo/bar"), true);
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

// aux-build:pub-use-extern-macros.rs

#![feature(use_extern_macros)]

extern crate macros;

// @has pub_use_extern_macros/macro.bar.html
pub use macros::bar;

// @has pub_use_extern_macros/macro.baz.html
// @!has pub_use_extern_macros/index.html 'pub use macros::baz;'
#[doc(inline)]
pub use macros::baz;

// @has pub_use_extern_macros/macro.quux.html
// @!has pub_use_extern_macros/index.html 'pub use macros::quux;'
#[doc(hidden)]
pub use macros::quux;
<commit_msg>update "pub-use-extern-macros" test to hide the regular import statement<commit_after>// Copyright 2017 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.

// aux-build:pub-use-extern-macros.rs

#![feature(use_extern_macros)]

extern crate macros;

// @has pub_use_extern_macros/macro.bar.html
// @!has pub_use_extern_macros/index.html 'pub use macros::bar;'
pub use macros::bar;

// @has pub_use_extern_macros/macro.baz.html
// @!has pub_use_extern_macros/index.html 'pub use macros::baz;'
#[doc(inline)]
pub use macros::baz;

// @has pub_use_extern_macros/macro.quux.html
// @!has pub_use_extern_macros/index.html 'pub use macros::quux;'
#[doc(hidden)]
pub use macros::quux;
<|endoftext|>


<commit_before>use crate::utils::{is_normalizable, last_path_segment, snippet};
use if_chain::if_chain;
use rustc_hir::{Expr, GenericArg, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};

/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
/// not available , use
/// the type's `ToString` implementation. In weird cases it could lead to types
/// with invalid `'_`
/// lifetime, but it should be rare.
pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String {
    let seg = last_path_segment(path);
    if_chain! {
        if let Some(ref params) = seg.args;
        if !params.parenthesized;
        if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
            GenericArg::Type(ty) => Some(ty),
            _ => None,
        }).nth(1);
        if let TyKind::Rptr(_, ref to_ty) = to_ty.kind;
        then {
            return snippet(cx, to_ty.ty.span, &to_ref_ty.to_string()).to_string();
        }
    }

    to_ref_ty.to_string()
}

// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
    let empty_param_env = ty::ParamEnv::empty();
    // check if `from` and `to` are normalizable to avoid ICE (#4968)
    if !(is_normalizable(cx, empty_param_env, from) && is_normalizable(cx, empty_param_env, to)) {
        return false;
    }
    let from_ty_layout = cx.tcx.layout_of(empty_param_env.and(from));
    let to_ty_layout = cx.tcx.layout_of(empty_param_env.and(to));
    if let (Ok(from_layout), Ok(to_layout)) = (from_ty_layout, to_ty_layout) {
        from_layout.size != to_layout.size || from_layout.align != to_layout.align || from_layout.abi != to_layout.abi
    } else {
        // no idea about layout, so don't lint
        false
    }
}

/// Check if the type conversion can be expressed as a pointer cast, instead of
/// a transmute. In certain cases, including some invalid casts from array
/// references to pointers, this may cause additional errors to be emitted and/or
/// ICE error messages. This function will panic if that occurs.
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
    cx: &LateContext<'tcx>,
    e: &'tcx Expr<'_>,
    from_ty: Ty<'tcx>,
    to_ty: Ty<'tcx>,
) -> bool {
    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
    matches!(
        check_cast(cx, e, from_ty, to_ty),
        Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
    )
}

/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
pub(super) fn check_cast<'tcx>(
    cx: &LateContext<'tcx>,
    e: &'tcx Expr<'_>,
    from_ty: Ty<'tcx>,
    to_ty: Ty<'tcx>,
) -> Option<CastKind> {
    let hir_id = e.hir_id;
    let local_def_id = hir_id.owner;

    Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
        let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);

        // If we already have errors, we can't be sure we can pointer cast.
        assert!(
            !fn_ctxt.errors_reported_since_creation(),
            "Newly created FnCtxt contained errors"
        );

        if let Ok(check) = CastCheck::new(
            &fn_ctxt, e, from_ty, to_ty,
            // We won't show any error to the user, so we don't care what the span is here.
            DUMMY_SP, DUMMY_SP,
        ) {
            let res = check.do_check(&fn_ctxt);

            // do_check's documentation says that it might return Ok and create
            // errors in the fcx instead of returing Err in some cases. Those cases
            // should be filtered out before getting here.
            assert!(
                !fn_ctxt.errors_reported_since_creation(),
                "`fn_ctxt` contained errors after cast check!"
            );

            res.ok()
        } else {
            None
        }
    })
}
<commit_msg>Make check_cast private<commit_after>use crate::utils::{is_normalizable, last_path_segment, snippet};
use if_chain::if_chain;
use rustc_hir::{Expr, GenericArg, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};

/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
/// not available , use
/// the type's `ToString` implementation. In weird cases it could lead to types
/// with invalid `'_`
/// lifetime, but it should be rare.
pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String {
    let seg = last_path_segment(path);
    if_chain! {
        if let Some(ref params) = seg.args;
        if !params.parenthesized;
        if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
            GenericArg::Type(ty) => Some(ty),
            _ => None,
        }).nth(1);
        if let TyKind::Rptr(_, ref to_ty) = to_ty.kind;
        then {
            return snippet(cx, to_ty.ty.span, &to_ref_ty.to_string()).to_string();
        }
    }

    to_ref_ty.to_string()
}

// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
    let empty_param_env = ty::ParamEnv::empty();
    // check if `from` and `to` are normalizable to avoid ICE (#4968)
    if !(is_normalizable(cx, empty_param_env, from) && is_normalizable(cx, empty_param_env, to)) {
        return false;
    }
    let from_ty_layout = cx.tcx.layout_of(empty_param_env.and(from));
    let to_ty_layout = cx.tcx.layout_of(empty_param_env.and(to));
    if let (Ok(from_layout), Ok(to_layout)) = (from_ty_layout, to_ty_layout) {
        from_layout.size != to_layout.size || from_layout.align != to_layout.align || from_layout.abi != to_layout.abi
    } else {
        // no idea about layout, so don't lint
        false
    }
}

/// Check if the type conversion can be expressed as a pointer cast, instead of
/// a transmute. In certain cases, including some invalid casts from array
/// references to pointers, this may cause additional errors to be emitted and/or
/// ICE error messages. This function will panic if that occurs.
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
    cx: &LateContext<'tcx>,
    e: &'tcx Expr<'_>,
    from_ty: Ty<'tcx>,
    to_ty: Ty<'tcx>,
) -> bool {
    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
    matches!(
        check_cast(cx, e, from_ty, to_ty),
        Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
    )
}

/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
    let hir_id = e.hir_id;
    let local_def_id = hir_id.owner;

    Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
        let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);

        // If we already have errors, we can't be sure we can pointer cast.
        assert!(
            !fn_ctxt.errors_reported_since_creation(),
            "Newly created FnCtxt contained errors"
        );

        if let Ok(check) = CastCheck::new(
            &fn_ctxt, e, from_ty, to_ty,
            // We won't show any error to the user, so we don't care what the span is here.
            DUMMY_SP, DUMMY_SP,
        ) {
            let res = check.do_check(&fn_ctxt);

            // do_check's documentation says that it might return Ok and create
            // errors in the fcx instead of returing Err in some cases. Those cases
            // should be filtered out before getting here.
            assert!(
                !fn_ctxt.errors_reported_since_creation(),
                "`fn_ctxt` contained errors after cast check!"
            );

            res.ok()
        } else {
            None
        }
    })
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 module contains some useful constants.

#![deny(clippy::missing_docs_in_private_items)]

/// List of the built-in types names.
///
/// See also [the reference][reference-types] for a list of such types.
///
/// [reference-types]: https://doc.rust-lang.org/reference.html#types
pub const BUILTIN_TYPES: &[&str] = &[
    "i8",
    "u8",
    "i16",
    "u16",
    "i32",
    "u32",
    "i64",
    "u64",
    "isize",
    "usize",
    "f32",
    "f64",
    "bool",
    "str",
    "char",
];
<commit_msg>constants: add u128 i128 builtin types and fix outdated url<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 module contains some useful constants.

#![deny(clippy::missing_docs_in_private_items)]

/// List of the built-in types names.
///
/// See also [the reference][reference-types] for a list of such types.
///
/// [reference-types]: https://doc.rust-lang.org/reference/types.html
pub const BUILTIN_TYPES: &[&str] = &[
    "i8",
    "u8",
    "i16",
    "u16",
    "i32",
    "u32",
    "i64",
    "u64",
    "i128",
    "u128",
    "isize",
    "usize",
    "f32",
    "f64",
    "bool",
    "str",
    "char",
];
<|endoftext|>


<commit_before>extern crate shiplift;

use shiplift::Docker;

fn main() {
    let docker = Docker::new();
    for c in docker.containers().list().build().unwrap() {
        println!("container -> {:?}", c)
    }
}
<commit_msg>test more builder<commit_after>extern crate shiplift;

use shiplift::Docker;

fn main() {
    let docker = Docker::new();
    for c in docker.containers().list().sized().build().unwrap() {
        println!("container -> {:?}", c)
    }
}
<|endoftext|>


<commit_before>use crate::{Assist, AssistId, AssistCtx, ast_editor::{AstEditor, AstBuilder}};

use hir::db::HirDatabase;
use ra_syntax::{SmolStr, TreeArc};
use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner};
use ra_db::FilePosition;

enum AddMissingImplMembersMode {
    DefaultMethodsOnly,
    NoDefaultMethods,
}

pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    add_missing_impl_members_inner(
        ctx,
        AddMissingImplMembersMode::NoDefaultMethods,
        "add_impl_missing_members",
        "add missing impl members",
    )
}

pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    add_missing_impl_members_inner(
        ctx,
        AddMissingImplMembersMode::DefaultMethodsOnly,
        "add_impl_default_members",
        "add impl default members",
    )
}

fn add_missing_impl_members_inner(
    mut ctx: AssistCtx<impl HirDatabase>,
    mode: AddMissingImplMembersMode,
    assist_id: &'static str,
    label: &'static str,
) -> Option<Assist> {
    let impl_node = ctx.node_at_offset::<ast::ImplBlock>()?;
    let impl_item_list = impl_node.item_list()?;

    let trait_def = {
        let file_id = ctx.frange.file_id;
        let position = FilePosition { file_id, offset: impl_node.syntax().range().start() };
        let analyzer = hir::SourceAnalyzer::new(ctx.db, position.file_id, impl_node.syntax(), None);

        resolve_target_trait_def(ctx.db, &analyzer, impl_node)?
    };

    let missing_fns: Vec<_> = {
        let fn_def_opt = |kind| if let ImplItemKind::FnDef(def) = kind { Some(def) } else { None };
        let def_name = |def| -> Option<&SmolStr> { FnDef::name(def).map(ast::Name::text) };

        let trait_items =
            trait_def.syntax().descendants().find_map(ast::ItemList::cast)?.impl_items();
        let impl_items = impl_item_list.impl_items();

        let trait_fns = trait_items.map(ImplItem::kind).filter_map(fn_def_opt).collect::<Vec<_>>();
        let impl_fns = impl_items.map(ImplItem::kind).filter_map(fn_def_opt).collect::<Vec<_>>();

        trait_fns
            .into_iter()
            .filter(|t| def_name(t).is_some())
            .filter(|t| match mode {
                AddMissingImplMembersMode::DefaultMethodsOnly => t.body().is_some(),
                AddMissingImplMembersMode::NoDefaultMethods => t.body().is_none(),
            })
            .filter(|t| impl_fns.iter().all(|i| def_name(i) != def_name(t)))
            .collect()
    };
    if missing_fns.is_empty() {
        return None;
    }

    ctx.add_action(AssistId(assist_id), label, |edit| {
        let n_existing_items = impl_item_list.impl_items().count();
        let fns = missing_fns.into_iter().map(add_body_and_strip_docstring).collect::<Vec<_>>();

        let mut ast_editor = AstEditor::new(impl_item_list);
        if n_existing_items == 0 {
            ast_editor.make_multiline();
        }
        ast_editor.append_functions(fns.iter().map(|it| &**it));
        let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap();
        let cursor_poisition = first_new_item.syntax().range().start();
        ast_editor.into_text_edit(edit.text_edit_builder());

        edit.set_cursor(cursor_poisition);
    });

    ctx.build()
}

fn add_body_and_strip_docstring(fn_def: &ast::FnDef) -> TreeArc<ast::FnDef> {
    let mut ast_editor = AstEditor::new(fn_def);
    if fn_def.body().is_none() {
        ast_editor.set_body(&AstBuilder::<ast::Block>::single_expr(
            &AstBuilder::<ast::Expr>::unimplemented(),
        ));
    }
    ast_editor.strip_attrs_and_docs();
    ast_editor.ast().to_owned()
}

/// Given an `ast::ImplBlock`, resolves the target trait (the one being
/// implemented) to a `ast::TraitDef`.
fn resolve_target_trait_def(
    db: &impl HirDatabase,
    analyzer: &hir::SourceAnalyzer,
    impl_block: &ast::ImplBlock,
) -> Option<TreeArc<ast::TraitDef>> {
    let ast_path =
        impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?.path()?;

    match analyzer.resolve_path(db, &ast_path) {
        Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).1),
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_add_missing_impl_members() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo {
    fn foo(&self);
    fn bar(&self);
    fn baz(&self);
}

struct S;

impl Foo for S {
    fn bar(&self) {}
<|>
}",
            "
trait Foo {
    fn foo(&self);
    fn bar(&self);
    fn baz(&self);
}

struct S;

impl Foo for S {
    fn bar(&self) {}
    <|>fn foo(&self) { unimplemented!() }
    fn baz(&self) { unimplemented!() }

}",
        );
    }

    #[test]
    fn test_copied_overriden_members() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo {
    fn foo(&self);
    fn bar(&self) -> bool { true }
    fn baz(&self) -> u32 { 42 }
}

struct S;

impl Foo for S {
    fn bar(&self) {}
<|>
}",
            "
trait Foo {
    fn foo(&self);
    fn bar(&self) -> bool { true }
    fn baz(&self) -> u32 { 42 }
}

struct S;

impl Foo for S {
    fn bar(&self) {}
    <|>fn foo(&self) { unimplemented!() }

}",
        );
    }

    #[test]
    fn test_empty_impl_block() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S { <|> }",
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}",
        );
    }

    #[test]
    fn test_cursor_after_empty_impl_block() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {}<|>",
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}",
        )
    }

    #[test]
    fn test_empty_trait() {
        check_assist_not_applicable(
            add_missing_impl_members,
            "
trait Foo;
struct S;
impl Foo for S { <|> }",
        )
    }

    #[test]
    fn test_ignore_unnamed_trait_members_and_default_methods() {
        check_assist_not_applicable(
            add_missing_impl_members,
            "
trait Foo {
    fn (arg: u32);
    fn valid(some: u32) -> bool { false }
}
struct S;
impl Foo for S { <|> }",
        )
    }

    #[test]
    fn test_with_docstring_and_attrs() {
        check_assist(
            add_missing_impl_members,
            r#"
#[doc(alias = "test alias")]
trait Foo {
    /// doc string
    #[must_use]
    fn foo(&self);
}
struct S;
impl Foo for S {}<|>"#,
            r#"
#[doc(alias = "test alias")]
trait Foo {
    /// doc string
    #[must_use]
    fn foo(&self);
}
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}"#,
        )
    }

    #[test]
    fn test_default_methods() {
        check_assist(
            add_missing_default_members,
            "
trait Foo {
    fn valid(some: u32) -> bool { false }
    fn foo(some: u32) -> bool;
}
struct S;
impl Foo for S { <|> }",
            "
trait Foo {
    fn valid(some: u32) -> bool { false }
    fn foo(some: u32) -> bool;
}
struct S;
impl Foo for S {
    <|>fn valid(some: u32) -> bool { false }
}",
        )
    }

}
<commit_msg>Remove collect<commit_after>use crate::{Assist, AssistId, AssistCtx, ast_editor::{AstEditor, AstBuilder}};

use hir::db::HirDatabase;
use ra_syntax::{SmolStr, TreeArc};
use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner};
use ra_db::FilePosition;

enum AddMissingImplMembersMode {
    DefaultMethodsOnly,
    NoDefaultMethods,
}

pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    add_missing_impl_members_inner(
        ctx,
        AddMissingImplMembersMode::NoDefaultMethods,
        "add_impl_missing_members",
        "add missing impl members",
    )
}

pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    add_missing_impl_members_inner(
        ctx,
        AddMissingImplMembersMode::DefaultMethodsOnly,
        "add_impl_default_members",
        "add impl default members",
    )
}

fn add_missing_impl_members_inner(
    mut ctx: AssistCtx<impl HirDatabase>,
    mode: AddMissingImplMembersMode,
    assist_id: &'static str,
    label: &'static str,
) -> Option<Assist> {
    let impl_node = ctx.node_at_offset::<ast::ImplBlock>()?;
    let impl_item_list = impl_node.item_list()?;

    let trait_def = {
        let file_id = ctx.frange.file_id;
        let position = FilePosition { file_id, offset: impl_node.syntax().range().start() };
        let analyzer = hir::SourceAnalyzer::new(ctx.db, position.file_id, impl_node.syntax(), None);

        resolve_target_trait_def(ctx.db, &analyzer, impl_node)?
    };

    let missing_fns: Vec<_> = {
        let fn_def_opt = |kind| if let ImplItemKind::FnDef(def) = kind { Some(def) } else { None };
        let def_name = |def| -> Option<&SmolStr> { FnDef::name(def).map(ast::Name::text) };

        let trait_items =
            trait_def.syntax().descendants().find_map(ast::ItemList::cast)?.impl_items();
        let impl_items = impl_item_list.impl_items();

        let trait_fns = trait_items.map(ImplItem::kind).filter_map(fn_def_opt);
        let impl_fns = impl_items.map(ImplItem::kind).filter_map(fn_def_opt).collect::<Vec<_>>();

        trait_fns
            .filter(|t| def_name(t).is_some())
            .filter(|t| match mode {
                AddMissingImplMembersMode::DefaultMethodsOnly => t.body().is_some(),
                AddMissingImplMembersMode::NoDefaultMethods => t.body().is_none(),
            })
            .filter(|t| impl_fns.iter().all(|i| def_name(i) != def_name(t)))
            .collect()
    };
    if missing_fns.is_empty() {
        return None;
    }

    ctx.add_action(AssistId(assist_id), label, |edit| {
        let n_existing_items = impl_item_list.impl_items().count();
        let fns = missing_fns.into_iter().map(add_body_and_strip_docstring).collect::<Vec<_>>();

        let mut ast_editor = AstEditor::new(impl_item_list);
        if n_existing_items == 0 {
            ast_editor.make_multiline();
        }
        ast_editor.append_functions(fns.iter().map(|it| &**it));
        let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap();
        let cursor_poisition = first_new_item.syntax().range().start();
        ast_editor.into_text_edit(edit.text_edit_builder());

        edit.set_cursor(cursor_poisition);
    });

    ctx.build()
}

fn add_body_and_strip_docstring(fn_def: &ast::FnDef) -> TreeArc<ast::FnDef> {
    let mut ast_editor = AstEditor::new(fn_def);
    if fn_def.body().is_none() {
        ast_editor.set_body(&AstBuilder::<ast::Block>::single_expr(
            &AstBuilder::<ast::Expr>::unimplemented(),
        ));
    }
    ast_editor.strip_attrs_and_docs();
    ast_editor.ast().to_owned()
}

/// Given an `ast::ImplBlock`, resolves the target trait (the one being
/// implemented) to a `ast::TraitDef`.
fn resolve_target_trait_def(
    db: &impl HirDatabase,
    analyzer: &hir::SourceAnalyzer,
    impl_block: &ast::ImplBlock,
) -> Option<TreeArc<ast::TraitDef>> {
    let ast_path =
        impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?.path()?;

    match analyzer.resolve_path(db, &ast_path) {
        Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).1),
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_add_missing_impl_members() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo {
    fn foo(&self);
    fn bar(&self);
    fn baz(&self);
}

struct S;

impl Foo for S {
    fn bar(&self) {}
<|>
}",
            "
trait Foo {
    fn foo(&self);
    fn bar(&self);
    fn baz(&self);
}

struct S;

impl Foo for S {
    fn bar(&self) {}
    <|>fn foo(&self) { unimplemented!() }
    fn baz(&self) { unimplemented!() }

}",
        );
    }

    #[test]
    fn test_copied_overriden_members() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo {
    fn foo(&self);
    fn bar(&self) -> bool { true }
    fn baz(&self) -> u32 { 42 }
}

struct S;

impl Foo for S {
    fn bar(&self) {}
<|>
}",
            "
trait Foo {
    fn foo(&self);
    fn bar(&self) -> bool { true }
    fn baz(&self) -> u32 { 42 }
}

struct S;

impl Foo for S {
    fn bar(&self) {}
    <|>fn foo(&self) { unimplemented!() }

}",
        );
    }

    #[test]
    fn test_empty_impl_block() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S { <|> }",
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}",
        );
    }

    #[test]
    fn test_cursor_after_empty_impl_block() {
        check_assist(
            add_missing_impl_members,
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {}<|>",
            "
trait Foo { fn foo(&self); }
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}",
        )
    }

    #[test]
    fn test_empty_trait() {
        check_assist_not_applicable(
            add_missing_impl_members,
            "
trait Foo;
struct S;
impl Foo for S { <|> }",
        )
    }

    #[test]
    fn test_ignore_unnamed_trait_members_and_default_methods() {
        check_assist_not_applicable(
            add_missing_impl_members,
            "
trait Foo {
    fn (arg: u32);
    fn valid(some: u32) -> bool { false }
}
struct S;
impl Foo for S { <|> }",
        )
    }

    #[test]
    fn test_with_docstring_and_attrs() {
        check_assist(
            add_missing_impl_members,
            r#"
#[doc(alias = "test alias")]
trait Foo {
    /// doc string
    #[must_use]
    fn foo(&self);
}
struct S;
impl Foo for S {}<|>"#,
            r#"
#[doc(alias = "test alias")]
trait Foo {
    /// doc string
    #[must_use]
    fn foo(&self);
}
struct S;
impl Foo for S {
    <|>fn foo(&self) { unimplemented!() }
}"#,
        )
    }

    #[test]
    fn test_default_methods() {
        check_assist(
            add_missing_default_members,
            "
trait Foo {
    fn valid(some: u32) -> bool { false }
    fn foo(some: u32) -> bool;
}
struct S;
impl Foo for S { <|> }",
            "
trait Foo {
    fn valid(some: u32) -> bool { false }
    fn foo(some: u32) -> bool;
}
struct S;
impl Foo for S {
    <|>fn valid(some: u32) -> bool { false }
}",
        )
    }

}
<|endoftext|>


<commit_before>//! Parses ELF auxiliary vectors.
#![cfg_attr(
    any(
        target_arch = "aarch64",
        target_arch = "arm",
        target_arch = "powerpc64"
    ),
    allow(dead_code)
)]

/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 25;
/// Key to access the CPU Hardware capabilities 2 bitfield.
pub(crate) const AT_HWCAP2: usize = 26;

/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
///
/// If an entry cannot be read all the bits in the bitfield are set to zero.
/// This should be interpreted as all the features being disabled.
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
    pub hwcap: usize,
    pub hwcap2: usize,
}

/// ELF Auxiliary Vector
///
/// The auxiliary vector is a memory region in a running ELF program's stack
/// composed of (key: usize, value: usize) pairs.
///
/// The keys used in the aux vector are platform dependent. For FreeBSD, they are
/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given
/// CPU can be queried with the  `AT_HWCAP` and `AT_HWCAP2` keys.
///
/// Note that run-time feature detection is not invoked for features that can
/// be detected at compile-time.
///
/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
pub(crate) fn auxv() -> Result<AuxVec, ()> {
    if let Ok(hwcap) = archauxv(AT_HWCAP) {
        if let Ok(hwcap2) = archauxv(AT_HWCAP2) {
            if hwcap != 0 && hwcap2 != 0 {
                return Ok(AuxVec { hwcap, hwcap2 });
            }
        }
    }
    Err(())
}

/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
    use core::mem;

    #[derive(Copy, Clone)]
    #[repr(C)]
    pub struct Elf_Auxinfo {
        pub a_type: usize,
        pub a_un: unnamed,
    }
    #[derive(Copy, Clone)]
    #[repr(C)]
    pub union unnamed {
        pub a_val: libc::c_long,
        pub a_ptr: *mut libc::c_void,
        pub a_fcn: Option<unsafe extern "C" fn() -> ()>,
    }

    let mut auxv: [Elf_Auxinfo; 27] = [Elf_Auxinfo {
        a_type: 0,
        a_un: unnamed { a_val: 0 },
    }; 27];

    let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint;

    unsafe {
        let mut mib = [
            libc::CTL_KERN,
            libc::KERN_PROC,
            libc::KERN_PROC_AUXV,
            libc::getpid(),
        ];

        let ret = libc::sysctl(
            mib.as_mut_ptr(),
            mib.len() as u32,
            &mut auxv as *mut _ as *mut _,
            &mut len as *mut _ as *mut _,
            0 as *mut libc::c_void,
            0,
        );

        if ret != -1 {
            for i in 0..auxv.len() {
                if auxv[i].a_type == key {
                    return Ok(auxv[i].a_un.a_val as usize);
                }
            }
        }
    }
    return Ok(0);
}
<commit_msg>Support riscv64gc-unknown-freebsd (#1260)<commit_after>//! Parses ELF auxiliary vectors.
#![cfg_attr(
    any(
        target_arch = "aarch64",
        target_arch = "arm",
        target_arch = "powerpc64",
        target_arch = "riscv64"
    ),
    allow(dead_code)
)]

/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 25;
/// Key to access the CPU Hardware capabilities 2 bitfield.
pub(crate) const AT_HWCAP2: usize = 26;

/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
///
/// If an entry cannot be read all the bits in the bitfield are set to zero.
/// This should be interpreted as all the features being disabled.
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
    pub hwcap: usize,
    pub hwcap2: usize,
}

/// ELF Auxiliary Vector
///
/// The auxiliary vector is a memory region in a running ELF program's stack
/// composed of (key: usize, value: usize) pairs.
///
/// The keys used in the aux vector are platform dependent. For FreeBSD, they are
/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given
/// CPU can be queried with the  `AT_HWCAP` and `AT_HWCAP2` keys.
///
/// Note that run-time feature detection is not invoked for features that can
/// be detected at compile-time.
///
/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
pub(crate) fn auxv() -> Result<AuxVec, ()> {
    if let Ok(hwcap) = archauxv(AT_HWCAP) {
        if let Ok(hwcap2) = archauxv(AT_HWCAP2) {
            if hwcap != 0 && hwcap2 != 0 {
                return Ok(AuxVec { hwcap, hwcap2 });
            }
        }
    }
    Err(())
}

/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
    use core::mem;

    #[derive(Copy, Clone)]
    #[repr(C)]
    pub struct Elf_Auxinfo {
        pub a_type: usize,
        pub a_un: unnamed,
    }
    #[derive(Copy, Clone)]
    #[repr(C)]
    pub union unnamed {
        pub a_val: libc::c_long,
        pub a_ptr: *mut libc::c_void,
        pub a_fcn: Option<unsafe extern "C" fn() -> ()>,
    }

    let mut auxv: [Elf_Auxinfo; 27] = [Elf_Auxinfo {
        a_type: 0,
        a_un: unnamed { a_val: 0 },
    }; 27];

    let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint;

    unsafe {
        let mut mib = [
            libc::CTL_KERN,
            libc::KERN_PROC,
            libc::KERN_PROC_AUXV,
            libc::getpid(),
        ];

        let ret = libc::sysctl(
            mib.as_mut_ptr(),
            mib.len() as u32,
            &mut auxv as *mut _ as *mut _,
            &mut len as *mut _ as *mut _,
            0 as *mut libc::c_void,
            0,
        );

        if ret != -1 {
            for i in 0..auxv.len() {
                if auxv[i].a_type == key {
                    return Ok(auxv[i].a_un.a_val as usize);
                }
            }
        }
    }
    return Ok(0);
}
<|endoftext|>