<commit_before>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::num::Wrapping;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;
// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_STATE) -> DWORD;
extern "system" fn xinput_get_state_stub(_: DWORD, _: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = xinput_get_state_stub;

type XInputSetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_VIBRATION) -> DWORD;
extern "system" fn xinput_set_state_stub(_: DWORD, _: *mut XINPUT_VIBRATION) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_SET_STATE_PTR: XInputSetStateType = xinput_set_state_stub;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn win32_load_xinput() {
        //Version available on modern windows without DX SDK Install
        let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

        if xinput_module == 0 as HMODULE {
            //Version available on old windows without DX SDK Install
            xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
        }

        if xinput_module != 0 as HMODULE {
            XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
            XINPUT_SET_STATE_PTR = mem::transmute::<FARPROC, XInputSetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputSetState")));
        }
}

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: i16, y_offset: i16) {

    let width = buffer.width as i16;
    let height = buffer.height as i16;
    let bytes_per_pixel = buffer.bytes_per_pixel as i16;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x.wrapping_add(x_offset) as u8) << 0) as u32 + (((y.wrapping_add(-y_offset) as u8) as u32) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);
        win32_load_xinput();
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    let pad = controller_state.Gamepad;

                    let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += stick_x >> 12; }
                    if stick_y.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += stick_y >> 12; }

                    //XINPUT_SET_STATE_PTR(controller_index, &mut XINPUT_VIBRATION { wLeftMotorSpeed: 60000, wRightMotorSpeed: 60000 });
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset, y_offset);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
            let vk_code = w_param;
            let was_down = (l_param & 1 << 30) != 0;
            let is_down = (l_param & 1 << 31) == 0;

            if vk_code == 'W' as u64 {
            }
            if vk_code == 'A' as u64 {
            }
            if vk_code == 'S' as u64 {
            }
            if vk_code == 'D' as u64 {
            }
            if vk_code == 'Q' as u64 {
            }
            if vk_code == VK_UP as u64 {
            }
            if vk_code == VK_DOWN as u64 {
            }
            if vk_code == VK_LEFT as u64 {
            }
            if vk_code == VK_RIGHT as u64 {
            }
            if vk_code == VK_ESCAPE as u64 {
                if is_down != was_down {
                    println!("ESCAPE");
                }
            }
            if vk_code == VK_SPACE as u64 {
                println!("\n");
            }

        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<commit_msg>Fixed alt-f4<commit_after>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::num::Wrapping;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;
// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_STATE) -> DWORD;
extern "system" fn xinput_get_state_stub(_: DWORD, _: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = xinput_get_state_stub;

type XInputSetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_VIBRATION) -> DWORD;
extern "system" fn xinput_set_state_stub(_: DWORD, _: *mut XINPUT_VIBRATION) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_SET_STATE_PTR: XInputSetStateType = xinput_set_state_stub;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn win32_load_xinput() {
        //Version available on modern windows without DX SDK Install
        let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

        if xinput_module == 0 as HMODULE {
            //Version available on old windows without DX SDK Install
            xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
        }

        if xinput_module != 0 as HMODULE {
            XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
            XINPUT_SET_STATE_PTR = mem::transmute::<FARPROC, XInputSetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputSetState")));
        }
}

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: i16, y_offset: i16) {

    let width = buffer.width as i16;
    let height = buffer.height as i16;
    let bytes_per_pixel = buffer.bytes_per_pixel as i16;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x.wrapping_add(x_offset) as u8) << 0) as u32 + (((y.wrapping_add(-y_offset) as u8) as u32) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);
        win32_load_xinput();
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    let pad = controller_state.Gamepad;

                    let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += stick_x >> 12; }
                    if stick_y.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += stick_y >> 12; }

                    //XINPUT_SET_STATE_PTR(controller_index, &mut XINPUT_VIBRATION { wLeftMotorSpeed: 60000, wRightMotorSpeed: 60000 });
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset, y_offset);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
            let vk_code = w_param;
            let was_down = (l_param & 1 << 30) != 0;
            let is_down = (l_param & 1 << 31) == 0;
            let alt_down = (l_param & 1 << 29) != 0;

            if vk_code == 'W' as u64 {
            }
            if vk_code == 'A' as u64 {
            }
            if vk_code == 'S' as u64 {
            }
            if vk_code == 'D' as u64 {
            }
            if vk_code == 'Q' as u64 {
            }
            if vk_code == VK_UP as u64 {
            }
            if vk_code == VK_DOWN as u64 {
            }
            if vk_code == VK_LEFT as u64 {
            }
            if vk_code == VK_RIGHT as u64 {
            }
            if vk_code == VK_ESCAPE as u64 {
                if is_down != was_down {
                    println!("ESCAPE");
                }
            }
            if vk_code == VK_SPACE as u64 {
                println!("\n");
            }
            if vk_code == VK_F4 as u64 && alt_down {
                GLOBAL_RUNNING = false;
             }

        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<|endoftext|>


<commit_before>use cocoa::base::{class, id};
use cocoa::foundation::NSUInteger;
use objc::runtime::BOOL;
use MTLCompareFunction;

pub trait MTLSamplerDescriptor {
    unsafe fn new(_: Self) -> id {
        msg_send![class("MTLSamplerDescriptor"), new]
    }

    /// The address mode for the texture depth (r) coordinate.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerAddressModeClampToEdge`.
    unsafe fn rAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setRAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The address mode for the texture width (s) coordinate.
    ///
    /// # Discussion
    ///
    /// The default value is MTLSamplerAddressModeClampToEdge.
    unsafe fn sAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setSAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The address mode for the texture height (t) coordinate.
    ///
    /// # Discsussion
    ///
    /// The default value is `MTLSamplerAddressModeClampToEdge`.
    unsafe fn tAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setTAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The filtering option for combining pixels within one mipmap level when
    /// the sample footprint is larger than a pixel (minification).
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMinMagFilterNearest`.
    unsafe fn minFilter(self) -> MTLSamplerMinMagFilter;
    unsafe fn setMinFilter(self, minFilter: MTLSamplerMinMagFilter);

    /// The filtering operation for combining pixels within one mipmap level when
    /// the sample footprint is smaller than a pixel (magnification).
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMinMagFilterNearest`.
    unsafe fn magFilter(self) -> MTLSamplerMinMagFilter;
    unsafe fn setMagFilter(self, magFilter: MTLSamplerMinMagFilter);

    /// The filtering option for combining pixels between two mipmap levels.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMipFilterNotMipmapped`.
    unsafe fn mipFilter(self) -> MTLSamplerMipFilter;
    unsafe fn setMipFilter(self, mipFilter: MTLSamplerMipFilter);

    /// The minimum level of detail (LOD) to use when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// The default value is `0.0f`. Clamp values are ignored for texture sample
    /// variants that specify an explicit LOD
    unsafe fn lodMinClamp(self) -> f32;
    unsafe fn setLodMinClamp(self, lodMinClamp: f32);

    /// The maximum level of detail (LOD) to use when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// The default value is `FLT_MAX`. Clamp values are ignored for texture sample
    /// variants that specify an explicit LOD.
    unsafe fn lodMaxClamp(self) -> f32;
    unsafe fn setLodMaxClamp(self, lodMaxClamp: f32);

    /// Allows the driver to use an average level of detail (LOD) when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// If this value is YES, an average LOD may be used across four fragment shader threads.
    /// If this value is NO, no averaging is performed and each thread will access its own LOD.
    unsafe fn lodAverage(self) -> BOOL;
    unsafe fn setLodAverage(self, lodAverage: BOOL);

    /// The number of samples that can be taken to improve the quality of sample footprints that
    /// are anisotropic.
    ///
    /// # Discussion
    ///
    /// Values must be between `1` and `16`, inclusive. The default value is `1`.
    unsafe fn maxAnisotropy(self) -> NSUInteger;
    unsafe fn setMaxAnisotropy(self, maxAnisotropy: NSUInteger);

    /// A Boolean value that indicates whether texture coordinates are normalized to the
    /// range `[0.0, 1.0]`.
    ///
    /// # Discussion
    ///
    /// If `YES`, texture coordinates are from `0.0` to `1.0`. If `NO`, texture coordinates
    /// are from `0` to `width` for horizontal coordinates and `0` to `height` for vertical
    /// coordinates. The default value is `YES`.
    ///
    /// Non-normalized texture coordinates should only be used with 1D and 2D textures with
    /// the following conditions; otherwise, the results of sampling are undefined.
    ///
    /// * The `MTLSamplerAddressModeClampToEdge` or `MTLSamplerAddressModeClampToZero` address
    ///   mode.
    ///
    /// * The `MTLSamplerMipFilterNotMipmapped` mipmap filtering option.
    ///
    /// * `minFilter` and `magFilter` must be equal to each other.
    ///
    /// * `maxAnisotropy` must be `1`.
    unsafe fn normalizedCoordinates(self) -> BOOL;
    unsafe fn setNormalizedCoordinates(self, normalizedCoordinates: BOOL);

    /// The sampler comparison function used when sampling texels from a depth texture.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLCompareFunctionNever`.
    ///
    /// The `MTLFeatureSet_iOS_GPUFamily3_v1` and `MTLFeatureSet_OSX_GPUFamily1_v1` feature
    /// sets allow you to define a framework-side sampler comparison function for a
    /// `MTLSamplerState` object. All feature sets support shader-side sampler comparison
    /// functions, as described in the Metal Shading Language Guide.
    unsafe fn compareFunction(self) -> MTLCompareFunction;
    unsafe fn setCompareFunction(self, compareFunction: MTLCompareFunction);

    /// A string used to identify this sampler descriptor.
    unsafe fn label(self) -> id;
    unsafe fn setLabel(self, label: id);

    unsafe fn copy(self) -> id;
}

impl MTLSamplerDescriptor for id {
    unsafe fn rAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, rAddressMode]
    }

    unsafe fn setRAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setRAddressMode:addressMode]
    }

    unsafe fn sAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, sAddressMode]
    }

    unsafe fn setSAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setSAddressMode:addressMode]
    }

    unsafe fn tAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, tAddressMode]
    }

    unsafe fn setTAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setTAddressMode:addressMode]
    }

    unsafe fn minFilter(self) -> MTLSamplerMinMagFilter {
        msg_send![self, minFilter]
    }

    unsafe fn setMinFilter(self, minFilter: MTLSamplerMinMagFilter) {
        msg_send![self, setMinFilter:minFilter]
    }

    unsafe fn magFilter(self) -> MTLSamplerMinMagFilter {
        msg_send![self, magFilter]
    }

    unsafe fn setMagFilter(self, magFilter: MTLSamplerMinMagFilter) {
        msg_send![self, setMagFilter:magFilter]
    }

    unsafe fn mipFilter(self) -> MTLSamplerMipFilter {
        msg_send![self, mipFilter]
    }

    unsafe fn setMipFilter(self, mipFilter: MTLSamplerMipFilter) {
        msg_send![self, setMipFilter:mipFilter]
    }

    unsafe fn lodMinClamp(self) -> f32 {
        msg_send![self, lodMinClamp]
    }

    unsafe fn setLodMinClamp(self, lodMinClamp: f32) {
        msg_send![self, setLodMinClamp:lodMinClamp]
    }

    unsafe fn lodMaxClamp(self) -> f32 {
        msg_send![self, lodMaxClamp]
    }

    unsafe fn setLodMaxClamp(self, lodMaxClamp: f32) {
        msg_send![self, setLodMaxClamp:lodMaxClamp]
    }

    unsafe fn lodAverage(self) -> BOOL {
        msg_send![self, lodAverage]
    }

    unsafe fn setLodAverage(self, lodAverage: BOOL) {
        msg_send![self, setLodAverage:lodAverage]
    }

    unsafe fn maxAnisotropy(self) -> NSUInteger {
        msg_send![self, maxAnisotropy]
    }

    unsafe fn setMaxAnisotropy(self, maxAnisotropy: NSUInteger) {
        msg_send![self, setMaxAnisotropy:maxAnisotropy]
    }

    unsafe fn normalizedCoordinates(self) -> BOOL {
        msg_send![self, normalizedCoordinates]
    }

    unsafe fn setNormalizedCoordinates(self, normalizedCoordinates: BOOL) {
        msg_send![self, setNormalizedCoordinates:normalizedCoordinates]
    }

    unsafe fn compareFunction(self) -> MTLCompareFunction {
        msg_send![self, compareFunction]
    }

    unsafe fn setCompareFunction(self, compareFunction: MTLCompareFunction) {
        msg_send![self, setCompareFunction:compareFunction]
    }

    unsafe fn label(self) -> id {
        msg_send![self, label]
    }

    unsafe fn setLabel(self, label: id) {
        msg_send![self, setLabel:label]
    }

    unsafe fn copy(self) -> id {
        msg_send![self, copy]
    }
}

/// Modes that determine the texture coordinate at each pixel when a fetch
/// falls outside the bounds of a texture. Also known as wrapping mode.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerAddressMode {
    /// Texture coordinates are clamped between 0.0 and 1.0, inclusive.
    MTLSamplerAddressModeClampToEdge = 0,

    ///  Texture coordinates wrap to the other side of the texture, effectively
    /// keeping only the fractional part of the texture coordinate.
    MTLSamplerAddressModeRepeat = 2,

    /// Between -1.0 and 1.0, the texture coordinates are mirrored across the axis.
    /// Outside -1.0 and 1.0, the image is repeated.
    MTLSamplerAddressModeMirrorRepeat = 3,

    /// Out of range texture coordinates return transparent zero (0,0,0,0) for images
    /// with an alpha channel and return opaque zero (0,0,0,1) for images without an
    /// alpha channel.
    MTLSamplerAddressModeClampToZero = 4
}

/// Filtering options for determining which pixel value is returned within a mipmap level.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerMinMagFilter {
    /// Select the single pixel nearest to the sample point.
    MTLSamplerMinMagFilterNearest = 0,

    /// Select two pixels in each dimension and interpolate linearly between them. Not all
    /// devices support linear filtering for all formats. Integer textures can not use
    /// linear filtering on any device, and only some devices support linear filtering for
    ///Float textures.
    MTLSamplerMinMagFilterLinear = 1
}

/// Filtering options for determining what pixel value is returned with multiple mipmap
/// levels.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerMipFilter {
    /// The texture is sampled from mipmap level `0`. Other mipmap levels are ignored.
    MTLSamplerMipFilterNotMipmapped = 0,
    /// The nearest mipmap level is selected.
    MTLSamplerMipFilterNearest = 1,
    /// If the filter falls between mipmap levels, both levels are sampled and the results
    /// are determined by linear interpolation between levels.
    MTLSamplerMipFilterLinear = 2
}
<commit_msg>format<commit_after>use cocoa::base::{class, id};
use cocoa::foundation::NSUInteger;
use objc::runtime::BOOL;
use MTLCompareFunction;

pub trait MTLSamplerDescriptor {
    unsafe fn new(_: Self) -> id {
        msg_send![class("MTLSamplerDescriptor"), new]
    }

    /// The address mode for the texture depth (r) coordinate.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerAddressModeClampToEdge`.
    unsafe fn rAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setRAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The address mode for the texture width (s) coordinate.
    ///
    /// # Discussion
    ///
    /// The default value is MTLSamplerAddressModeClampToEdge.
    unsafe fn sAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setSAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The address mode for the texture height (t) coordinate.
    ///
    /// # Discsussion
    ///
    /// The default value is `MTLSamplerAddressModeClampToEdge`.
    unsafe fn tAddressMode(self) -> MTLSamplerAddressMode;
    unsafe fn setTAddressMode(self, addressMode: MTLSamplerAddressMode);

    /// The filtering option for combining pixels within one mipmap level when
    /// the sample footprint is larger than a pixel (minification).
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMinMagFilterNearest`.
    unsafe fn minFilter(self) -> MTLSamplerMinMagFilter;
    unsafe fn setMinFilter(self, minFilter: MTLSamplerMinMagFilter);

    /// The filtering operation for combining pixels within one mipmap level when
    /// the sample footprint is smaller than a pixel (magnification).
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMinMagFilterNearest`.
    unsafe fn magFilter(self) -> MTLSamplerMinMagFilter;
    unsafe fn setMagFilter(self, magFilter: MTLSamplerMinMagFilter);

    /// The filtering option for combining pixels between two mipmap levels.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLSamplerMipFilterNotMipmapped`.
    unsafe fn mipFilter(self) -> MTLSamplerMipFilter;
    unsafe fn setMipFilter(self, mipFilter: MTLSamplerMipFilter);

    /// The minimum level of detail (LOD) to use when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// The default value is `0.0f`. Clamp values are ignored for texture sample
    /// variants that specify an explicit LOD
    unsafe fn lodMinClamp(self) -> f32;
    unsafe fn setLodMinClamp(self, lodMinClamp: f32);

    /// The maximum level of detail (LOD) to use when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// The default value is `FLT_MAX`. Clamp values are ignored for texture sample
    /// variants that specify an explicit LOD.
    unsafe fn lodMaxClamp(self) -> f32;
    unsafe fn setLodMaxClamp(self, lodMaxClamp: f32);

    /// Allows the driver to use an average level of detail (LOD) when sampling from a texture.
    ///
    /// # Discussion
    ///
    /// If this value is YES, an average LOD may be used across four fragment shader threads.
    /// If this value is NO, no averaging is performed and each thread will access its own LOD.
    unsafe fn lodAverage(self) -> BOOL;
    unsafe fn setLodAverage(self, lodAverage: BOOL);

    /// The number of samples that can be taken to improve the quality of sample footprints that
    /// are anisotropic.
    ///
    /// # Discussion
    ///
    /// Values must be between `1` and `16`, inclusive. The default value is `1`.
    unsafe fn maxAnisotropy(self) -> NSUInteger;
    unsafe fn setMaxAnisotropy(self, maxAnisotropy: NSUInteger);

    /// A Boolean value that indicates whether texture coordinates are normalized to the
    /// range `[0.0, 1.0]`.
    ///
    /// # Discussion
    ///
    /// If `YES`, texture coordinates are from `0.0` to `1.0`. If `NO`, texture coordinates
    /// are from `0` to `width` for horizontal coordinates and `0` to `height` for vertical
    /// coordinates. The default value is `YES`.
    ///
    /// Non-normalized texture coordinates should only be used with 1D and 2D textures with
    /// the following conditions; otherwise, the results of sampling are undefined.
    ///
    /// * The `MTLSamplerAddressModeClampToEdge` or `MTLSamplerAddressModeClampToZero` address
    ///   mode.
    ///
    /// * The `MTLSamplerMipFilterNotMipmapped` mipmap filtering option.
    ///
    /// * `minFilter` and `magFilter` must be equal to each other.
    ///
    /// * `maxAnisotropy` must be `1`.
    unsafe fn normalizedCoordinates(self) -> BOOL;
    unsafe fn setNormalizedCoordinates(self, normalizedCoordinates: BOOL);

    /// The sampler comparison function used when sampling texels from a depth texture.
    ///
    /// # Discussion
    ///
    /// The default value is `MTLCompareFunctionNever`.
    ///
    /// The `MTLFeatureSet_iOS_GPUFamily3_v1` and `MTLFeatureSet_OSX_GPUFamily1_v1` feature
    /// sets allow you to define a framework-side sampler comparison function for a
    /// `MTLSamplerState` object. All feature sets support shader-side sampler comparison
    /// functions, as described in the Metal Shading Language Guide.
    unsafe fn compareFunction(self) -> MTLCompareFunction;
    unsafe fn setCompareFunction(self, compareFunction: MTLCompareFunction);

    /// A string used to identify this sampler descriptor.
    unsafe fn label(self) -> id;
    unsafe fn setLabel(self, label: id);

    unsafe fn copy(self) -> id;
}

impl MTLSamplerDescriptor for id {
    unsafe fn rAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, rAddressMode]
    }

    unsafe fn setRAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setRAddressMode:addressMode]
    }

    unsafe fn sAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, sAddressMode]
    }

    unsafe fn setSAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setSAddressMode:addressMode]
    }

    unsafe fn tAddressMode(self) -> MTLSamplerAddressMode {
        msg_send![self, tAddressMode]
    }

    unsafe fn setTAddressMode(self, addressMode: MTLSamplerAddressMode) {
        msg_send![self, setTAddressMode:addressMode]
    }

    unsafe fn minFilter(self) -> MTLSamplerMinMagFilter {
        msg_send![self, minFilter]
    }

    unsafe fn setMinFilter(self, minFilter: MTLSamplerMinMagFilter) {
        msg_send![self, setMinFilter:minFilter]
    }

    unsafe fn magFilter(self) -> MTLSamplerMinMagFilter {
        msg_send![self, magFilter]
    }

    unsafe fn setMagFilter(self, magFilter: MTLSamplerMinMagFilter) {
        msg_send![self, setMagFilter:magFilter]
    }

    unsafe fn mipFilter(self) -> MTLSamplerMipFilter {
        msg_send![self, mipFilter]
    }

    unsafe fn setMipFilter(self, mipFilter: MTLSamplerMipFilter) {
        msg_send![self, setMipFilter:mipFilter]
    }

    unsafe fn lodMinClamp(self) -> f32 {
        msg_send![self, lodMinClamp]
    }

    unsafe fn setLodMinClamp(self, lodMinClamp: f32) {
        msg_send![self, setLodMinClamp:lodMinClamp]
    }

    unsafe fn lodMaxClamp(self) -> f32 {
        msg_send![self, lodMaxClamp]
    }

    unsafe fn setLodMaxClamp(self, lodMaxClamp: f32) {
        msg_send![self, setLodMaxClamp:lodMaxClamp]
    }

    unsafe fn lodAverage(self) -> BOOL {
        msg_send![self, lodAverage]
    }

    unsafe fn setLodAverage(self, lodAverage: BOOL) {
        msg_send![self, setLodAverage:lodAverage]
    }

    unsafe fn maxAnisotropy(self) -> NSUInteger {
        msg_send![self, maxAnisotropy]
    }

    unsafe fn setMaxAnisotropy(self, maxAnisotropy: NSUInteger) {
        msg_send![self, setMaxAnisotropy:maxAnisotropy]
    }

    unsafe fn normalizedCoordinates(self) -> BOOL {
        msg_send![self, normalizedCoordinates]
    }

    unsafe fn setNormalizedCoordinates(self, normalizedCoordinates: BOOL) {
        msg_send![self, setNormalizedCoordinates:normalizedCoordinates]
    }

    unsafe fn compareFunction(self) -> MTLCompareFunction {
        msg_send![self, compareFunction]
    }

    unsafe fn setCompareFunction(self, compareFunction: MTLCompareFunction) {
        msg_send![self, setCompareFunction:compareFunction]
    }

    unsafe fn label(self) -> id {
        msg_send![self, label]
    }

    unsafe fn setLabel(self, label: id) {
        msg_send![self, setLabel:label]
    }

    unsafe fn copy(self) -> id {
        msg_send![self, copy]
    }
}

/// Modes that determine the texture coordinate at each pixel when a fetch
/// falls outside the bounds of a texture. Also known as wrapping mode.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerAddressMode {
    /// Texture coordinates are clamped between 0.0 and 1.0, inclusive.
    MTLSamplerAddressModeClampToEdge = 0,

    ///  Texture coordinates wrap to the other side of the texture, effectively
    /// keeping only the fractional part of the texture coordinate.
    MTLSamplerAddressModeRepeat = 2,

    /// Between -1.0 and 1.0, the texture coordinates are mirrored across the axis.
    /// Outside -1.0 and 1.0, the image is repeated.
    MTLSamplerAddressModeMirrorRepeat = 3,

    /// Out of range texture coordinates return transparent zero (0,0,0,0) for images
    /// with an alpha channel and return opaque zero (0,0,0,1) for images without an
    /// alpha channel.
    MTLSamplerAddressModeClampToZero = 4
}

/// Filtering options for determining which pixel value is returned within a mipmap level.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerMinMagFilter {
    /// Select the single pixel nearest to the sample point.
    MTLSamplerMinMagFilterNearest = 0,

    /// Select two pixels in each dimension and interpolate linearly between them. Not all
    /// devices support linear filtering for all formats. Integer textures can not use
    /// linear filtering on any device, and only some devices support linear filtering for
    ///Float textures.
    MTLSamplerMinMagFilterLinear = 1
}

/// Filtering options for determining what pixel value is returned with multiple mipmap
/// levels.
#[repr(usize)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum MTLSamplerMipFilter {
    /// The texture is sampled from mipmap level `0`. Other mipmap levels are ignored.
    MTLSamplerMipFilterNotMipmapped = 0,
    /// The nearest mipmap level is selected.
    MTLSamplerMipFilterNearest = 1,
    /// If the filter falls between mipmap levels, both levels are sampled and the results
    /// are determined by linear interpolation between levels.
    MTLSamplerMipFilterLinear = 2
}
<|endoftext|>


<commit_before>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// https://bn.gy provider
    BnGy,
    /// https://is.gd provider
    IsGd,
    /// http://psbe.co provider
    PsbeCo,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::BnGy => "bn.gy",
            Provider::IsGd => "is.gd",
            Provider::PsbeCo => "psbe.co",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::Vgd,
        Provider::Rdd,

        // The following list are items that are discouraged from use.
        Provider::PsbeCo,
        Provider::Rlu,
    ]
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::BnGy => bngy_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::BnGy => bngy_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<commit_msg>Build fail fix<commit_after>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// https://bn.gy provider
    BnGy,
    /// https://is.gd provider
    IsGd,
    /// http://psbe.co provider
    PsbeCo,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::BnGy => "bn.gy",
            Provider::IsGd => "is.gd",
            Provider::PsbeCo => "psbe.co",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::VGd,
        Provider::Rdd,

        // The following list are items that are discouraged from use.
        Provider::PsbeCo,
        Provider::Rlu,
    ]
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::BnGy => bngy_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::BnGy => bngy_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<|endoftext|>


<commit_before>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// https://bn.gy provider
    BnGy,
    /// http://fifo.cc provider
    FifoCc,
    /// https://hec.su provider
    ///
    /// * Limited to 3000 API requests per day
    HecSu,
    /// https://is.gd provider
    IsGd,
    /// http://nowlinks.net provider
    NowLinks,
    /// http://phx.co.in provider
    /// After some time shows ads
    PhxCoIn,
    /// http://psbe.co provider
    PsbeCo,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    ///
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// http://tinyurl.com provider
    /// * Note: this service does not provide any API.
    /// The implementation result depends on the service result web page.
    TinyUrl,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::BnGy => "bn.gy",
            Provider::FifoCc => "fifo.cc",
            Provider::HecSu => "hec.su",
            Provider::IsGd => "is.gd",
            Provider::NowLinks => "nowlinks.net",
            Provider::PhxCoIn => "phx.co.in",
            Provider::PsbeCo => "psbe.co",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::TinyUrl => "tinyurl.com",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::VGd,
        Provider::Rdd,
        Provider::FifoCc,

        // The following list are items that are discouraged from use.
        // Reason: rate limit (100 requests per hour)
        Provider::Rlu,
        // Reason: rate limit (3000 requests per day)
        Provider::HecSu,
        // Reason: does not provide an api
        Provider::TinyUrl,
        // Reason: unstable work
        Provider::PsbeCo,

        // The following list are items that show previews instead of direct links.
        Provider::NowLinks,

        // The following list are items that show ads and have a timeout before
        // you may go on the original link.
        Provider::PhxCoIn,
    ]
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn fifocc_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"shortner\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        short_url = format!("http://fifo.cc/{}", short_url);
        Some(short_url)
    } else {
        None
    }
}

fn fifocc_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://fifo.cc/api/v2?url={}", url))
        .send()
        .ok()
}

fn hecsu_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<short>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</short>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn hecsu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://hec.su/api?url={}&method=xml", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn nowlinks_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn nowlinks_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://nowlinks.net/api?url={}", url))
        .send()
        .ok()
}

fn phxcoin_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn phxcoin_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://phx.co.in/shrink.asp?url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn tinyurl_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("data-clipboard-text=\"")
                      .nth(1).unwrap_or("")
                      .split("\">").next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tinyurl_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tinyurl.com/create.php?url={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::BnGy => bngy_parse(res),
        Provider::FifoCc => fifocc_parse(res),
        Provider::HecSu => hecsu_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::NowLinks => nowlinks_parse(res),
        Provider::PhxCoIn => phxcoin_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::TinyUrl => tinyurl_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::BnGy => bngy_request(url, client),
        Provider::FifoCc => fifocc_request(url, client),
        Provider::HecSu => hecsu_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::NowLinks => nowlinks_request(url, client),
        Provider::PhxCoIn => phxcoin_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::TinyUrl => tinyurl_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<commit_msg>BamBz provider implemented<commit_after>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};
use hyper::header::ContentType;

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// https://bam.bz provider
    BamBz,
    /// https://bn.gy provider
    BnGy,
    /// http://fifo.cc provider
    FifoCc,
    /// https://hec.su provider
    ///
    /// * Limited to 3000 API requests per day
    HecSu,
    /// https://is.gd provider
    IsGd,
    /// http://nowlinks.net provider
    NowLinks,
    /// http://phx.co.in provider
    /// After some time shows ads
    PhxCoIn,
    /// http://psbe.co provider
    PsbeCo,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    ///
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// http://tinyurl.com provider
    /// * Note: this service does not provide any API.
    /// The implementation result depends on the service result web page.
    TinyUrl,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::BamBz => "bam.bz",
            Provider::BnGy => "bn.gy",
            Provider::FifoCc => "fifo.cc",
            Provider::HecSu => "hec.su",
            Provider::IsGd => "is.gd",
            Provider::NowLinks => "nowlinks.net",
            Provider::PhxCoIn => "phx.co.in",
            Provider::PsbeCo => "psbe.co",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::TinyUrl => "tinyurl.com",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::VGd,
        Provider::Rdd,
        Provider::BamBz,
        Provider::FifoCc,

        // The following list are items that are discouraged from use.
        // Reason: rate limit (100 requests per hour)
        Provider::Rlu,
        // Reason: rate limit (3000 requests per day)
        Provider::HecSu,
        // Reason: does not provide an api
        Provider::TinyUrl,
        // Reason: unstable work
        Provider::PsbeCo,

        // The following list are items that show previews instead of direct links.
        Provider::NowLinks,

        // The following list are items that show ads and have a timeout before
        // you may go on the original link.
        Provider::PhxCoIn,
    ]
}

fn bambz_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        Some(string.to_owned().replace("\\", ""))
    } else {
        None
    }
}

fn bambz_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://bam.bz/api/short")
        .body(&format!("target={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn fifocc_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"shortner\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        short_url = format!("http://fifo.cc/{}", short_url);
        Some(short_url)
    } else {
        None
    }
}

fn fifocc_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://fifo.cc/api/v2?url={}", url))
        .send()
        .ok()
}

fn hecsu_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<short>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</short>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn hecsu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://hec.su/api?url={}&method=xml", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn nowlinks_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn nowlinks_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://nowlinks.net/api?url={}", url))
        .send()
        .ok()
}

fn phxcoin_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn phxcoin_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://phx.co.in/shrink.asp?url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn tinyurl_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("data-clipboard-text=\"")
                      .nth(1).unwrap_or("")
                      .split("\">").next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tinyurl_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tinyurl.com/create.php?url={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::BamBz => bambz_parse(res),
        Provider::BnGy => bngy_parse(res),
        Provider::FifoCc => fifocc_parse(res),
        Provider::HecSu => hecsu_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::NowLinks => nowlinks_parse(res),
        Provider::PhxCoIn => phxcoin_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::TinyUrl => tinyurl_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::BamBz => bambz_request(url, client),
        Provider::BnGy => bngy_request(url, client),
        Provider::FifoCc => fifocc_request(url, client),
        Provider::HecSu => hecsu_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::NowLinks => nowlinks_request(url, client),
        Provider::PhxCoIn => phxcoin_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::TinyUrl => tinyurl_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<|endoftext|>


<commit_before>use std::ops::Index;

use library;
use nameutil;
use version::Version;

pub type NsId = u16;
pub const MAIN: NsId = library::MAIN_NAMESPACE;
pub const INTERNAL: NsId = library::INTERNAL_NAMESPACE;

#[derive(Debug)]
pub struct Namespace {
    pub name: String,
    pub crate_name: String,
    pub ffi_crate_name: String,
    pub higher_crate_name: String,
    pub package_name: Option<String>,
    pub shared_libs: Vec<String>,
    pub versions: Vec<Version>,
}

#[derive(Debug)]
pub struct Info {
    namespaces: Vec<Namespace>,
    pub glib_ns_id: NsId,
}

impl Info {
    pub fn main(&self) -> &Namespace {
        &self[MAIN]
    }
}

impl Index<NsId> for Info {
    type Output = Namespace;

    fn index(&self, index: NsId) -> &Namespace {
        &self.namespaces[index as usize]
    }
}

pub fn run(gir: &library::Library) -> Info {
    let mut namespaces = Vec::with_capacity(gir.namespaces.len());
    let mut glib_ns_id = None;

    for (ns_id, ns) in gir.namespaces.iter().enumerate() {
        let ns_id = ns_id as NsId;
        let crate_name = nameutil::crate_name(&ns.name);
        let ffi_crate_name = if ns_id == MAIN {
            "ffi".to_owned()
        } else {
            format!("{}_ffi", crate_name)
        };
        let higher_crate_name = match &crate_name[..] {
            "gobject" => "glib".to_owned(),
            _ => crate_name.clone(),
        };
        namespaces.push(Namespace {
            name: ns.name.clone(),
            crate_name,
            ffi_crate_name,
            higher_crate_name,
            package_name: ns.package_name.clone(),
            shared_libs: ns.shared_library.clone(),
            versions: ns.versions.iter().cloned().collect(),
        });
        if ns.name == "GLib" {
            glib_ns_id = Some(ns_id);
        }
    }

    Info {
        namespaces,
        glib_ns_id: glib_ns_id.expect("Missing `GLib` namespace!"),
    }
}
<commit_msg>Fix namespaces ffi_crate for GObject<commit_after>use std::ops::Index;

use library;
use nameutil;
use version::Version;

pub type NsId = u16;
pub const MAIN: NsId = library::MAIN_NAMESPACE;
pub const INTERNAL: NsId = library::INTERNAL_NAMESPACE;

#[derive(Debug)]
pub struct Namespace {
    pub name: String,
    pub crate_name: String,
    pub ffi_crate_name: String,
    pub higher_crate_name: String,
    pub package_name: Option<String>,
    pub shared_libs: Vec<String>,
    pub versions: Vec<Version>,
}

#[derive(Debug)]
pub struct Info {
    namespaces: Vec<Namespace>,
    pub glib_ns_id: NsId,
}

impl Info {
    pub fn main(&self) -> &Namespace {
        &self[MAIN]
    }
}

impl Index<NsId> for Info {
    type Output = Namespace;

    fn index(&self, index: NsId) -> &Namespace {
        &self.namespaces[index as usize]
    }
}

pub fn run(gir: &library::Library) -> Info {
    let mut namespaces = Vec::with_capacity(gir.namespaces.len());
    let mut glib_ns_id = None;
    let mut is_gobject = false;

    for (ns_id, ns) in gir.namespaces.iter().enumerate() {
        let ns_id = ns_id as NsId;
        let crate_name = nameutil::crate_name(&ns.name);
        let mut is_local_ffi = ns_id == MAIN;
        if is_local_ffi && ns.name == "GObject" {
            is_gobject = true;
            is_local_ffi = false;
        } else if is_gobject && ns.name == "GLib" {
            is_local_ffi = true;
        }
        let ffi_crate_name = if is_local_ffi {
            "ffi".to_owned()
        } else {
            format!("{}_ffi", crate_name)
        };
        let higher_crate_name = match &crate_name[..] {
            "gobject" => "glib".to_owned(),
            _ => crate_name.clone(),
        };
        namespaces.push(Namespace {
            name: ns.name.clone(),
            crate_name,
            ffi_crate_name,
            higher_crate_name,
            package_name: ns.package_name.clone(),
            shared_libs: ns.shared_library.clone(),
            versions: ns.versions.iter().cloned().collect(),
        });
        if ns.name == "GLib" {
            glib_ns_id = Some(ns_id);
        }
    }

    Info {
        namespaces,
        glib_ns_id: glib_ns_id.expect("Missing `GLib` namespace!"),
    }
}
<|endoftext|>


<commit_before>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::Serializer;
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(with = "u64_handler")]
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(deserialize_with = "deserialize_action",
            rename = "action_type",
            serialize_with = "serialize_action")]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    pub delete_member_days: String,
    /// Number of members removed by the prune
    pub members_removed: String,
    /// Channel in which the messages were deleted
    pub channel_id: ChannelId,
    /// Number of deleted messages.
    pub count: u32,
    /// Id of the overwritten entity
    pub id: u64,
    /// Type of overwritten entity ("member" or "role").
    #[serde(rename = "type")] pub kind: String,
    /// Name of the role if type is "role"
    pub role_name: String,
}

mod u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<u64, D::Error> {
        struct U64Visitor;

        impl<'de> Visitor<'de> for U64Visitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer or a string with a valid number inside")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<u64, E> {
                Ok(val)
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<u64, E> {
                string.parse().map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_any(U64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &u64, s: S) -> StdResult<S::Ok, S::Error> {
        s.serialize_u64(*num)
    }
}

fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
    struct ActionVisitor;

    impl<'de> Visitor<'de> for ActionVisitor {
        type Value = Action;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 1 to 72")
        }

        // NOTE: Serde internally delegates number types below `u64` to it.
        fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<Action, E> {
            let value = value as u8;

            Ok(match value {
                1 => Action::GuildUpdate,
                10...12 => Action::Channel(unsafe { transmute(value) }),
                13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                20...25 => Action::Member(unsafe { transmute(value) }),
                30...32 => Action::Role(unsafe { transmute(value) }),
                40...42 => Action::Invite(unsafe { transmute(value) }),
                50...52 => Action::Webhook(unsafe { transmute(value) }),
                60...62 => Action::Emoji(unsafe { transmute(value) }),
                72 => Action::MessageDelete,
                _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
            })
        }
    }

    de.deserialize_any(ActionVisitor)
}

fn serialize_action<S: Serializer>(
    action: &Action,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    serializer.serialize_u8(action.num())
}

impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<commit_msg>Turn the number-like properties of `Options` into `u64`<commit_after>use internal::prelude::*;
use serde::de::{
    self,
    Deserialize,
    Deserializer,
    MapAccess,
    Visitor
};
use serde::ser::Serializer;
use super::super::prelude::*;
use std::{
    collections::HashMap,
    mem::transmute,
    fmt
};

/// Determines to what entity an action was used on.
#[derive(Debug)]
#[repr(u8)]
pub enum Target {
    Guild = 10,
    Channel = 20,
    User = 30,
    Role = 40,
    Invite = 50,
    Webhook = 60,
    Emoji = 70,
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    MessageDelete,
}

impl Action {
    pub fn num(&self) -> u8 {
        use self::Action::*;

        match *self {
            GuildUpdate => 1,
            Action::Channel(ref x) => x.num(),
            Action::ChannelOverwrite(ref x) => x.num(),
            Action::Member(ref x) => x.num(),
            Action::Role(ref x) => x.num(),
            Action::Invite(ref x) => x.num(),
            Action::Webhook(ref x) => x.num(),
            Action::Emoji(ref x) => x.num(),
            Action::MessageDelete => 72,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannel {
    Create = 10,
    Update = 11,
    Delete = 12,
}

impl ActionChannel {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannel::Create => 10,
            ActionChannel::Update => 11,
            ActionChannel::Delete => 12,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionChannelOverwrite {
    Create = 13,
    Update = 14,
    Delete = 15,
}

impl ActionChannelOverwrite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionChannelOverwrite::Create => 13,
            ActionChannelOverwrite::Update => 14,
            ActionChannelOverwrite::Delete => 15,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
}

impl ActionMember {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMember::Kick => 20,
            ActionMember::Prune => 21,
            ActionMember::BanAdd => 22,
            ActionMember::BanRemove => 23,
            ActionMember::Update => 24,
            ActionMember::RoleUpdate => 25,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionRole {
    Create = 30,
    Update = 31,
    Delete = 32,
}

impl ActionRole {
    pub fn num(&self) -> u8 {
        match *self {
            ActionRole::Create => 30,
            ActionRole::Update => 31,
            ActionRole::Delete => 32,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionInvite {
    Create = 40,
    Update = 41,
    Delete = 42,
}

impl ActionInvite {
    pub fn num(&self) -> u8 {
        match *self {
            ActionInvite::Create => 40,
            ActionInvite::Update => 41,
            ActionInvite::Delete => 42,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionWebhook {
    Create = 50,
    Update = 51,
    Delete = 52,
}

impl ActionWebhook {
    pub fn num(&self) -> u8 {
        match *self {
            ActionWebhook::Create => 50,
            ActionWebhook::Update => 51,
            ActionWebhook::Delete => 52,
        }
    }
}

#[derive(Debug)]
#[repr(u8)]
pub enum ActionEmoji {
    Create = 60,
    Delete = 61,
    Update = 62,
}

impl ActionEmoji {
    pub fn num(&self) -> u8 {
        match *self {
            ActionEmoji::Create => 60,
            ActionEmoji::Update => 61,
            ActionEmoji::Delete => 62,
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Change {
    #[serde(rename = "key")] pub name: String,
    // TODO: Change these to an actual type.
    #[serde(rename = "old_value")] pub old: String,
    #[serde(rename = "new_value")] pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(with = "u64_handler")]
    pub target_id: u64,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(
        with = "action_handler",
        rename = "action_type"
    )]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Option<Vec<Change>>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
    /// Some optional data assosiated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Options {
    /// Number of days after which inactive members were kicked.
    #[serde(with = "u64_handler")]
    pub delete_member_days: u64,
    /// Number of members removed by the prune
    #[serde(with = "u64_handler")]
    pub members_removed: u64,
    /// Channel in which the messages were deleted
    pub channel_id: ChannelId,
    /// Number of deleted messages.
    #[serde(with = "u64_handler")]
    pub count: u64,
    /// Id of the overwritten entity
    pub id: u64,
    /// Type of overwritten entity ("member" or "role").
    #[serde(rename = "type")] pub kind: String,
    /// Name of the role if type is "role"
    pub role_name: String,
}

mod u64_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(des: D) -> StdResult<u64, D::Error> {
        struct U64Visitor;

        impl<'de> Visitor<'de> for U64Visitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer or a string with a valid number inside")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, val: u64) -> StdResult<u64, E> {
                Ok(val)
            }

            fn visit_str<E: de::Error>(self, string: &str) -> StdResult<u64, E> {
                string.parse().map_err(|e| de::Error::custom(e))
            }
        }

        des.deserialize_any(U64Visitor)
    }

    pub fn serialize<S: Serializer>(num: &u64, s: S) -> StdResult<S::Ok, S::Error> {
        s.serialize_u64(*num)
    }
}

mod action_handler {
    use super::*;

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> StdResult<Action, D::Error> {
        struct ActionVisitor;

        impl<'de> Visitor<'de> for ActionVisitor {
            type Value = Action;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an integer between 1 to 72")
            }

            // NOTE: Serde internally delegates number types below `u64` to it.
            fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<Action, E> {
                let value = value as u8;

                Ok(match value {
                    1 => Action::GuildUpdate,
                    10...12 => Action::Channel(unsafe { transmute(value) }),
                    13...15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
                    20...25 => Action::Member(unsafe { transmute(value) }),
                    30...32 => Action::Role(unsafe { transmute(value) }),
                    40...42 => Action::Invite(unsafe { transmute(value) }),
                    50...52 => Action::Webhook(unsafe { transmute(value) }),
                    60...62 => Action::Emoji(unsafe { transmute(value) }),
                    72 => Action::MessageDelete,
                    _ => return Err(E::custom(format!("Unexpected action number: {}", value))),
                })
            }
        }

        de.deserialize_any(ActionVisitor)
    }

    pub fn serialize<S: Serializer>(
        action: &Action,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u8(action.num())
    }
}
impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")] Entries,
            #[serde(rename = "webhooks")] Webhooks,
            #[serde(rename = "users")] Users,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<AuditLogs, V::Error> {
                let mut audit_log_entries = None;
                let mut users = None;
                let mut webhooks = None;

                while let Some(field) = map.next_key()? {
                    match field {
                        Field::Entries => {
                            if audit_log_entries.is_some() {
                                return Err(de::Error::duplicate_field("entries"));
                            }

                            audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
                        },
                        Field::Webhooks => {
                            if webhooks.is_some() {
                                return Err(de::Error::duplicate_field("webhooks"));
                            }

                            webhooks = Some(map.next_value::<Vec<Webhook>>()?);
                        },
                        Field::Users => {
                            if users.is_some() {
                                return Err(de::Error::duplicate_field("users"));
                            }

                            users = Some(map.next_value::<Vec<User>>()?);
                        },
                    }
                }

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .unwrap()
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                    webhooks: webhooks.unwrap(),
                    users: users.unwrap(),
                })
            }
        }

        const FIELD: &[&str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<|endoftext|>