<commit_before>#![allow(unstable)]

extern crate x11;
extern crate libc;

use std::ptr;
use std::ffi;
use std::mem;
use std::str;
use std::slice;
use std::boxed::Box;

use x11::xlib;
use x11::xlib::{ Display, Window };
use libc::{ c_int, c_long, c_uint, c_ulong, c_void };

#[derive(Debug, Copy, Clone)]
pub struct Context {
    pub display: *mut Display,

}

pub fn open_display(name: Option<&str>) -> Option<Context> {
    unsafe{
        let display = match name {
            Some(n) => {
                let s = ffi::CString::new(n).unwrap();
                xlib::XOpenDisplay(s.as_ptr())
            }
            None => { xlib::XOpenDisplay(ptr::null()) }
        };

        if display == ptr::null_mut() {
            None
        }
        else{
            // let b = Some(Box::<Display>::new(*display));
            // xlib::XFree(display as *mut libc::c_void);
            // b
            let c = Context {
                display: display,
            };
            Some(c)
        }
    }
}

pub fn close_display(context: Context) {
    unsafe{
        xlib::XCloseDisplay(context.display);
    }
}

pub fn default_screen(context: Context) -> c_int {
    unsafe{
        xlib::XDefaultScreen(context.display)
    }
}

pub fn create_window(context: Context, parent: Window, x: c_int, y: c_int, width: c_uint, height: c_uint) -> Window{
    unsafe {
        xlib::XCreateSimpleWindow(context.display, parent, x, y, width, height, 0, 0, 0)
    }
}

pub fn root_window(context: Context, screen_num: c_int) -> c_ulong {
    unsafe {
        xlib::XRootWindow(context.display, screen_num)
    }
}

pub fn next_event(context: Context) -> xlib::XEvent {
    unsafe{
        let mut e: xlib::XEvent = mem::zeroed();
        xlib::XNextEvent(context.display, &mut e);
        e
    }
}

pub fn define_cursor(context: Context, window: Window, shape: c_uint) {
    unsafe {
        let cursor = xlib::XCreateFontCursor(context.display, shape);
        xlib::XDefineCursor(context.display, window, cursor);
    }
}

pub fn grab_key(context: Context, keycode: xlib::KeyCode, modifiers: c_uint, window: Window) {
    unsafe {
        xlib::XGrabKey(context.display, keycode as c_int, modifiers, window, 1, xlib::GrabModeAsync, xlib::GrabModeAsync);
    }
}

pub fn grab_button(context: Context, button: c_uint, modifiers: c_uint, window: Window) {
    unsafe {
        xlib::XGrabButton(context.display, button, modifiers, window,
                          0,
                          xlib::ButtonPressMask as c_uint,
                          xlib::GrabModeAsync, xlib::GrabModeAsync,
                          0, 0);
    }
}

pub fn ungrab_button(context: Context, button: c_uint, modifiers: c_uint, window: Window) {
    unsafe{
        xlib::XUngrabButton(context.display, button, modifiers, window);
    }
}

pub fn get_atom_name(context: Context, atom: xlib::Atom) -> Option<String> {
    unsafe{
        let name = xlib::XGetAtomName(context.display, atom);
        if name == ptr::null_mut() {
            return None
        }
        let s = ffi::CStr::from_ptr(name);
        let s = s.to_bytes();
        match str::from_utf8(s) {
            Ok(v) => {
                let tmp = Some(v.to_string());
                xlib::XFree(name as *mut libc::c_void);
                tmp
            }
            _ => None
        }
    }
}

pub fn get_atom(context: Context, name: &str) -> xlib::Atom{
    unsafe{
        let cstr = ffi::CString::new(name).unwrap();
        let atom = xlib::XInternAtom(context.display, cstr.as_ptr(), xlib::False);
        atom
    }
}

pub fn get_text_property(context: Context, window: xlib::Window, atom: xlib::Atom) -> Option<String>{
    unsafe{
        let mut prop: xlib::XTextProperty = mem::zeroed();
        let r = xlib::XGetTextProperty(context.display, window, &mut prop, atom);
        if r == 0 || prop.nitems == 0{
            None
        }else{

            // let s = String::from_raw_parts(prop.value, prop.nitems as usize, prop.nitems as usize).clone()
            let s = slice::from_raw_parts(prop.value, prop.nitems as usize).iter().map(|&c| c as u8).collect();
            match String::from_utf8(s) {
                Ok(v) => {
                    xlib::XFree(prop.value as *mut libc::c_void);
                    Some(v)
                }
                _ => None
            }
        }
    }
}

pub fn get_wm_protocols(context: Context, window: Window) -> Vec<xlib::Atom>{
    unsafe{
        let mut atoms: *mut xlib::Atom = ptr::null_mut();
        let mut count = 0;
        let s = xlib::XGetWMProtocols(context.display, window, &mut atoms, &mut count);
        let mut vec: Vec<xlib::Atom> = Vec::new();
        if s > 0 {
            vec = slice::from_raw_parts(atoms, count as usize).iter()
                .map(|&a| a as xlib::Atom).collect();
            xlib::XFree(atoms as *mut c_void);
        }
        vec
    }
}

pub fn get_window_attributes(context: Context, window: Window) -> xlib::XWindowAttributes {
    unsafe{
        let mut attrs: xlib::XWindowAttributes = mem::zeroed();
        xlib::XGetWindowAttributes(context.display, window, &mut attrs);
        attrs
    }
}

pub fn set_window_attributes(context: Context, window: Window, mask: c_ulong, mut attrs: xlib::XSetWindowAttributes) {
    unsafe {
        xlib::XChangeWindowAttributes(context.display, window, mask, &mut attrs);
    }
}
pub fn get_transient_for_hint(context: Context, window: Window) -> i32 {
    unsafe{
        let mut window_return: xlib::Window = 0;
        xlib::XGetTransientForHint(context.display, window, &mut window_return)
    }
}

pub fn change_window_attributes(context: Context, window: Window, valuemask: c_ulong, attrs: *mut xlib::XSetWindowAttributes) {
    unsafe{
        xlib::XChangeWindowAttributes(context.display, window, valuemask, attrs);
    }

}

fn get_window_property(context: Context, window: Window, atom: xlib::Atom) {
    unsafe {
        let mut actual_type_return: u64 = 0;
        let mut actual_format_return: i32 = 0;
        let mut nitem_return: libc::c_ulong = 0;
        let mut bytes_after_return: libc::c_ulong = 0;
        let mut prop_return: *mut libc::c_uchar = mem::zeroed();

        let r = xlib::XGetWindowProperty(context.display, window, atom,
                                         0, 0xFFFFFFFF, 0, 0,
                                         &mut actual_type_return,
                                         &mut actual_format_return,
                                         &mut nitem_return,
                                         &mut bytes_after_return,
                                         &mut prop_return);

        debug!("result get wp {}", r);
        if r == 0 {

        }else{
            debug!("actual format return {}", actual_format_return);
            if actual_format_return == 0 {

            }
            else {
                // let s = from_raw_parts(prop_return as *const libc::c_ulong, nitems_return as usize).iter()
                //     .map(|&c| c as u64)
                //     .collect();
                let s = String::from_raw_parts(prop_return, nitem_return as usize, nitem_return as usize);
                println!("{}", s);

            }
        }
    }
}

pub fn get_top_window(context: Context, window: Window)-> Option<Window>{
    println!("get top window {}", window);
    let mut w = window;
    let mut root = 0;
    let mut parent = 0;
    loop {
        let res = query_tree(context, w);
        match res {
            Some((r, p, _)) => {
                if r == p {
                    break;
                }
                else{
                    w = parent;
                    parent = p;
                    root = r;
                    println!("p {}", parent);
                    println!("r {}", r);
                }
            }
            None => {
                return None
            }
        }
    }
    Some(w)
}

pub fn get_children(context: Context, window: Window) -> Option<Vec<Window>> {
    let res = query_tree(context, window);
    match res {
        Some((_, _, v)) => {
            Some(v)
        }
        None => { None }
    }
}

pub fn reparent(context: Context, window: Window, parent: Window, x: c_int, y: c_int) {
    unsafe {
        xlib::XReparentWindow(context.display, window, parent, x, y);
    }
}
pub fn query_tree(context: Context, window: Window) -> Option<(Window, Window, Vec<Window>)> {
    let mut root: Window = 0;
    let mut parent: Window = window;
    let mut children: *mut Window = ptr::null_mut();
    let mut nchildren: libc::c_uint = 0;
    unsafe{
        let s = xlib::XQueryTree(context.display, window, &mut root, &mut parent, &mut children, &mut nchildren);
        if s > 0 {
            let vec = slice::from_raw_parts(children,
                                            nchildren as usize).iter()
                .map(|&a| a as Window).collect();
            xlib::XFree(children as *mut libc::c_void);
            Some((root, parent, vec))
        }
        else{
            None
        }
    }

}

pub fn lookup_keysym(event: xlib::XKeyEvent, index: c_int) -> c_ulong{
    let mut e = event;
    unsafe{
        xlib::XLookupKeysym(&mut e, index)
    }
}

// pub fn loopup_string(event: xlib::XKeyEvent) -> Option<(c_ulong, String)>{
//     let mut sym: xlib::KeySym = 0;
//     let status: *mut xlib::XComposeStatus = ptr::null_mut();

//     unsafe{
//         let mut e = event;
//         xlib::XLookupString(&mut e, ptr::null_mut(), 0, &mut sym, status);
//     }

// }

pub fn set_input_focus(context: Context, window: Window) {
    let none = 0;
    let pointer_root = 1;
    let parent = 2;
    unsafe{
        let (old, _) = get_input_focus(context);
        debug!("set focus from {} to {}", old, window);
        xlib::XSetInputFocus(context.display, window, none, 0);
    }
}

pub fn get_input_focus(context: Context) -> (Window, c_int){
    let mut window: xlib::Window = 0;
    let mut revert_to: libc::c_int = 0;
    unsafe{
        let s = xlib::XGetInputFocus(context.display, &mut window, &mut revert_to);
    }
    (window, revert_to)
}

pub fn unmap_window(context: Context, window: Window) -> c_int{
    unsafe{
        xlib::XUnmapWindow(context.display, window)
    }
}

pub fn configure_window(context: Context, window: Window, mask:c_uint, mut change: xlib::XWindowChanges) {
    unsafe{
        xlib::XConfigureWindow(context.display, window, mask, &mut change);
    }
}
pub fn map_window(context: Context, window: Window) -> c_int{
    unsafe{
        xlib::XMapWindow(context.display, window)
    }
}

pub fn kill_window(context: Context, window: Window) {
    let mut event: xlib::XClientMessageEvent = unsafe {
        mem::zeroed()
    };

    let display = context.display;
    let wm_delete_window = get_atom(context, "WM_DELETE_WINDOW");
    let wm_protocols = get_atom(context, "WM_PROTOCOLS");
    let protocols = get_wm_protocols(context, window);

    if protocols.iter().any(|&p| p == wm_delete_window){
        event.type_ = xlib::ClientMessage;
        event.message_type = wm_protocols;
        event.format = 32;
        event.window = window;
        event.send_event = xlib::True;
        event.display = display;
        event.data.set_long(0, wm_delete_window as libc::c_long);

        let e: xlib::XEvent = From::from(event);
        send_event(context, window, xlib::True, xlib::NoEventMask, e);
    }
    else{
        unsafe{
            xlib::XKillClient(display, window);
        }
    }

}

pub fn send_event(context: Context, window: Window,
                  propagate: c_int, event_mask: c_long,
                  mut event: xlib::XEvent) {
    unsafe{
        xlib::XSendEvent(context.display, window, propagate, event_mask, &mut event);
    }
}

pub fn keysym_to_string(keysym: c_ulong) -> Option<String> {
    let status: *mut xlib::XComposeStatus = ptr::null_mut();
    unsafe{
        let s = xlib::XKeysymToString(keysym);
        let cstr = ffi::CStr::from_ptr(s);
        match str::from_utf8(cstr.to_bytes()) {
            Ok(s) => {
                Some(s.to_string())
            }
            _ => {
                None
            }
        }
    }
}

pub fn keysym_to_keycode(context: Context, keysym: xlib::KeySym) -> xlib::KeyCode {
    unsafe {
        xlib::XKeysymToKeycode(context.display, keysym)
    }
}

pub fn string_to_keysym(s: &str) -> xlib::KeySym {
    let tmp = ffi::CString::new(s).unwrap();
    unsafe{
        xlib::XStringToKeysym(tmp.as_ptr())
    }

}

pub fn select_input(context: Context, window: Window, mask: c_long) {
    unsafe{
        xlib::XSelectInput(context.display, window, mask);
    }
}

pub fn sync(context: Context, discard: c_int) {
    unsafe {
        xlib::XSync(context.display, discard);
    }
}

pub fn create_gc(context: Context, drawable: xlib::Drawable, mask: c_ulong, mut values: xlib::XGCValues) -> xlib::GC{
    unsafe {
        xlib::XCreateGC(context.display, drawable, mask, &mut values)
    }
}

pub fn default_gc(context: Context, screen_num: c_int) -> xlib::GC{
    unsafe {
        xlib::XDefaultGC(context.display, screen_num)
    }
}

pub fn display_height(context: Context, screen_num: c_int) -> c_int{
    unsafe{
        xlib::XDisplayHeight(context.display, screen_num)
    }
}

pub fn display_width(context: Context, screen_num: c_int) -> c_int{
    unsafe{
        xlib::XDisplayWidth(context.display, screen_num)
    }
}

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

#[test]
fn test_open(){
    let display = open_display(None);
    assert!(display.is_some());
}

}
<commit_msg>add more info to context<commit_after>#![allow(unstable)]

extern crate x11;
extern crate libc;

use std::ptr;
use std::ffi;
use std::mem;
use std::str;
use std::slice;
use std::boxed::Box;

use x11::xlib;
use x11::xlib::{ Display, Window };
use libc::{ c_int, c_long, c_uint, c_ulong, c_void };

#[derive(Debug, Copy, Clone)]
pub struct Context {
    pub display: *mut Display,
    pub screen_num: c_int,
    pub root: Window,
}

pub fn open_display(name: Option<&str>) -> Option<Context> {
    unsafe{
        let display = match name {
            Some(n) => {
                let s = ffi::CString::new(n).unwrap();
                xlib::XOpenDisplay(s.as_ptr())
            }
            None => { xlib::XOpenDisplay(ptr::null()) }
        };

        if display == ptr::null_mut() {
            None
        }
        else{
            // let b = Some(Box::<Display>::new(*display));
            // xlib::XFree(display as *mut libc::c_void);
            // b
            let c = Context {
                display: display,
                screen_num: 0,
                root: 0,
            };
            Some(c)
        }
    }
}

pub fn close_display(context: Context) {
    unsafe{
        xlib::XCloseDisplay(context.display);
    }
}

pub fn default_screen(context: Context) -> c_int {
    unsafe{
        xlib::XDefaultScreen(context.display)
    }
}

pub fn create_window(context: Context, parent: Window, x: c_int, y: c_int, width: c_uint, height: c_uint) -> Window{
    unsafe {
        xlib::XCreateSimpleWindow(context.display, parent, x, y, width, height, 0, 0, 0)
    }
}

pub fn root_window(context: Context, screen_num: c_int) -> c_ulong {
    unsafe {
        xlib::XRootWindow(context.display, screen_num)
    }
}

pub fn next_event(context: Context) -> xlib::XEvent {
    unsafe{
        let mut e: xlib::XEvent = mem::zeroed();
        xlib::XNextEvent(context.display, &mut e);
        e
    }
}

pub fn define_cursor(context: Context, window: Window, shape: c_uint) {
    unsafe {
        let cursor = xlib::XCreateFontCursor(context.display, shape);
        xlib::XDefineCursor(context.display, window, cursor);
    }
}

pub fn grab_key(context: Context, keycode: xlib::KeyCode, modifiers: c_uint, window: Window) {
    unsafe {
        xlib::XGrabKey(context.display, keycode as c_int, modifiers, window, 1, xlib::GrabModeAsync, xlib::GrabModeAsync);
    }
}

pub fn grab_button(context: Context, button: c_uint, modifiers: c_uint, window: Window) {
    unsafe {
        xlib::XGrabButton(context.display, button, modifiers, window,
                          0,
                          xlib::ButtonPressMask as c_uint,
                          xlib::GrabModeAsync, xlib::GrabModeAsync,
                          0, 0);
    }
}

pub fn ungrab_button(context: Context, button: c_uint, modifiers: c_uint, window: Window) {
    unsafe{
        xlib::XUngrabButton(context.display, button, modifiers, window);
    }
}

pub fn get_atom_name(context: Context, atom: xlib::Atom) -> Option<String> {
    unsafe{
        let name = xlib::XGetAtomName(context.display, atom);
        if name == ptr::null_mut() {
            return None
        }
        let s = ffi::CStr::from_ptr(name);
        let s = s.to_bytes();
        match str::from_utf8(s) {
            Ok(v) => {
                let tmp = Some(v.to_string());
                xlib::XFree(name as *mut libc::c_void);
                tmp
            }
            _ => None
        }
    }
}

pub fn get_atom(context: Context, name: &str) -> xlib::Atom{
    unsafe{
        let cstr = ffi::CString::new(name).unwrap();
        let atom = xlib::XInternAtom(context.display, cstr.as_ptr(), xlib::False);
        atom
    }
}

pub fn get_text_property(context: Context, window: xlib::Window, atom: xlib::Atom) -> Option<String>{
    unsafe{
        let mut prop: xlib::XTextProperty = mem::zeroed();
        let r = xlib::XGetTextProperty(context.display, window, &mut prop, atom);
        if r == 0 || prop.nitems == 0{
            None
        }else{

            // let s = String::from_raw_parts(prop.value, prop.nitems as usize, prop.nitems as usize).clone()
            let s = slice::from_raw_parts(prop.value, prop.nitems as usize).iter().map(|&c| c as u8).collect();
            match String::from_utf8(s) {
                Ok(v) => {
                    xlib::XFree(prop.value as *mut libc::c_void);
                    Some(v)
                }
                _ => None
            }
        }
    }
}

pub fn get_wm_protocols(context: Context, window: Window) -> Vec<xlib::Atom>{
    unsafe{
        let mut atoms: *mut xlib::Atom = ptr::null_mut();
        let mut count = 0;
        let s = xlib::XGetWMProtocols(context.display, window, &mut atoms, &mut count);
        let mut vec: Vec<xlib::Atom> = Vec::new();
        if s > 0 {
            vec = slice::from_raw_parts(atoms, count as usize).iter()
                .map(|&a| a as xlib::Atom).collect();
            xlib::XFree(atoms as *mut c_void);
        }
        vec
    }
}

pub fn get_window_attributes(context: Context, window: Window) -> xlib::XWindowAttributes {
    unsafe{
        let mut attrs: xlib::XWindowAttributes = mem::zeroed();
        xlib::XGetWindowAttributes(context.display, window, &mut attrs);
        attrs
    }
}

pub fn set_window_attributes(context: Context, window: Window, mask: c_ulong, mut attrs: xlib::XSetWindowAttributes) {
    unsafe {
        xlib::XChangeWindowAttributes(context.display, window, mask, &mut attrs);
    }
}
pub fn get_transient_for_hint(context: Context, window: Window) -> i32 {
    unsafe{
        let mut window_return: xlib::Window = 0;
        xlib::XGetTransientForHint(context.display, window, &mut window_return)
    }
}

pub fn change_window_attributes(context: Context, window: Window, valuemask: c_ulong, attrs: *mut xlib::XSetWindowAttributes) {
    unsafe{
        xlib::XChangeWindowAttributes(context.display, window, valuemask, attrs);
    }

}

fn get_window_property(context: Context, window: Window, atom: xlib::Atom) {
    unsafe {
        let mut actual_type_return: u64 = 0;
        let mut actual_format_return: i32 = 0;
        let mut nitem_return: libc::c_ulong = 0;
        let mut bytes_after_return: libc::c_ulong = 0;
        let mut prop_return: *mut libc::c_uchar = mem::zeroed();

        let r = xlib::XGetWindowProperty(context.display, window, atom,
                                         0, 0xFFFFFFFF, 0, 0,
                                         &mut actual_type_return,
                                         &mut actual_format_return,
                                         &mut nitem_return,
                                         &mut bytes_after_return,
                                         &mut prop_return);

        debug!("result get wp {}", r);
        if r == 0 {

        }else{
            debug!("actual format return {}", actual_format_return);
            if actual_format_return == 0 {

            }
            else {
                // let s = from_raw_parts(prop_return as *const libc::c_ulong, nitems_return as usize).iter()
                //     .map(|&c| c as u64)
                //     .collect();
                let s = String::from_raw_parts(prop_return, nitem_return as usize, nitem_return as usize);
                println!("{}", s);

            }
        }
    }
}

pub fn get_top_window(context: Context, window: Window)-> Option<Window>{
    println!("get top window {}", window);
    let mut w = window;
    let mut root = 0;
    let mut parent = 0;
    loop {
        let res = query_tree(context, w);
        match res {
            Some((r, p, _)) => {
                if r == p {
                    break;
                }
                else{
                    w = parent;
                    parent = p;
                    root = r;
                    println!("p {}", parent);
                    println!("r {}", r);
                }
            }
            None => {
                return None
            }
        }
    }
    Some(w)
}

pub fn get_children(context: Context, window: Window) -> Option<Vec<Window>> {
    let res = query_tree(context, window);
    match res {
        Some((_, _, v)) => {
            Some(v)
        }
        None => { None }
    }
}

pub fn reparent(context: Context, window: Window, parent: Window, x: c_int, y: c_int) {
    unsafe {
        xlib::XReparentWindow(context.display, window, parent, x, y);
    }
}
pub fn query_tree(context: Context, window: Window) -> Option<(Window, Window, Vec<Window>)> {
    let mut root: Window = 0;
    let mut parent: Window = window;
    let mut children: *mut Window = ptr::null_mut();
    let mut nchildren: libc::c_uint = 0;
    unsafe{
        let s = xlib::XQueryTree(context.display, window, &mut root, &mut parent, &mut children, &mut nchildren);
        if s > 0 {
            let vec = slice::from_raw_parts(children,
                                            nchildren as usize).iter()
                .map(|&a| a as Window).collect();
            xlib::XFree(children as *mut libc::c_void);
            Some((root, parent, vec))
        }
        else{
            None
        }
    }

}

pub fn lookup_keysym(event: xlib::XKeyEvent, index: c_int) -> c_ulong{
    let mut e = event;
    unsafe{
        xlib::XLookupKeysym(&mut e, index)
    }
}

// pub fn loopup_string(event: xlib::XKeyEvent) -> Option<(c_ulong, String)>{
//     let mut sym: xlib::KeySym = 0;
//     let status: *mut xlib::XComposeStatus = ptr::null_mut();

//     unsafe{
//         let mut e = event;
//         xlib::XLookupString(&mut e, ptr::null_mut(), 0, &mut sym, status);
//     }

// }

pub fn set_input_focus(context: Context, window: Window) {
    let none = 0;
    let pointer_root = 1;
    let parent = 2;
    unsafe{
        let (old, _) = get_input_focus(context);
        debug!("set focus from {} to {}", old, window);
        xlib::XSetInputFocus(context.display, window, none, 0);
    }
}

pub fn get_input_focus(context: Context) -> (Window, c_int){
    let mut window: xlib::Window = 0;
    let mut revert_to: libc::c_int = 0;
    unsafe{
        let s = xlib::XGetInputFocus(context.display, &mut window, &mut revert_to);
    }
    (window, revert_to)
}

pub fn unmap_window(context: Context, window: Window) -> c_int{
    unsafe{
        xlib::XUnmapWindow(context.display, window)
    }
}

pub fn configure_window(context: Context, window: Window, mask:c_uint, mut change: xlib::XWindowChanges) {
    unsafe{
        xlib::XConfigureWindow(context.display, window, mask, &mut change);
    }
}
pub fn map_window(context: Context, window: Window) -> c_int{
    unsafe{
        xlib::XMapWindow(context.display, window)
    }
}

pub fn kill_window(context: Context, window: Window) {
    let mut event: xlib::XClientMessageEvent = unsafe {
        mem::zeroed()
    };

    let display = context.display;
    let wm_delete_window = get_atom(context, "WM_DELETE_WINDOW");
    let wm_protocols = get_atom(context, "WM_PROTOCOLS");
    let protocols = get_wm_protocols(context, window);

    if protocols.iter().any(|&p| p == wm_delete_window){
        event.type_ = xlib::ClientMessage;
        event.message_type = wm_protocols;
        event.format = 32;
        event.window = window;
        event.send_event = xlib::True;
        event.display = display;
        event.data.set_long(0, wm_delete_window as libc::c_long);

        let e: xlib::XEvent = From::from(event);
        send_event(context, window, xlib::True, xlib::NoEventMask, e);
    }
    else{
        unsafe{
            xlib::XKillClient(display, window);
        }
    }

}

pub fn send_event(context: Context, window: Window,
                  propagate: c_int, event_mask: c_long,
                  mut event: xlib::XEvent) {
    unsafe{
        xlib::XSendEvent(context.display, window, propagate, event_mask, &mut event);
    }
}

pub fn keysym_to_string(keysym: c_ulong) -> Option<String> {
    let status: *mut xlib::XComposeStatus = ptr::null_mut();
    unsafe{
        let s = xlib::XKeysymToString(keysym);
        let cstr = ffi::CStr::from_ptr(s);
        match str::from_utf8(cstr.to_bytes()) {
            Ok(s) => {
                Some(s.to_string())
            }
            _ => {
                None
            }
        }
    }
}

pub fn keysym_to_keycode(context: Context, keysym: xlib::KeySym) -> xlib::KeyCode {
    unsafe {
        xlib::XKeysymToKeycode(context.display, keysym)
    }
}

pub fn string_to_keysym(s: &str) -> xlib::KeySym {
    let tmp = ffi::CString::new(s).unwrap();
    unsafe{
        xlib::XStringToKeysym(tmp.as_ptr())
    }

}

pub fn select_input(context: Context, window: Window, mask: c_long) {
    unsafe{
        xlib::XSelectInput(context.display, window, mask);
    }
}

pub fn sync(context: Context, discard: c_int) {
    unsafe {
        xlib::XSync(context.display, discard);
    }
}

pub fn create_gc(context: Context, drawable: xlib::Drawable, mask: c_ulong, mut values: xlib::XGCValues) -> xlib::GC{
    unsafe {
        xlib::XCreateGC(context.display, drawable, mask, &mut values)
    }
}

pub fn default_gc(context: Context, screen_num: c_int) -> xlib::GC{
    unsafe {
        xlib::XDefaultGC(context.display, screen_num)
    }
}

pub fn display_height(context: Context, screen_num: c_int) -> c_int{
    unsafe{
        xlib::XDisplayHeight(context.display, screen_num)
    }
}

pub fn display_width(context: Context, screen_num: c_int) -> c_int{
    unsafe{
        xlib::XDisplayWidth(context.display, screen_num)
    }
}

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

#[test]
fn test_open(){
    let display = open_display(None);
    assert!(display.is_some());
}

}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use toml;

use dependency::Dependency;

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
        ParseError(error: String, loline: usize, locol: usize, hiline: usize, hicol: usize) {
            description("parse error")
            display("{}:{}{} {}",
                loline + 1, locol + 1,
                if loline != hiline || locol != hicol {
                    format!("-{}:{}", hiline + 1,
                            hicol + 1)
                } else {
                    "".to_string()
                },
                error)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, Clone, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<(), Box<Error>> {
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));

        let new_contents = format!("[{}]\n{}{}",
                                   proj_header,
                                   proj_data,
                                   toml::Value::Table(toml));
        let new_contents_bytes = new_contents.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        try!(file.set_len(new_contents_bytes.len() as u64));
        file.write_all(new_contents_bytes).map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             dep: &Dependency)
                             -> Result<(), ManifestError> {
        let (ref name, ref data) = dep.to_toml();
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert_with(|| toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    ///     assert!(manifest.data.is_empty());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(mut section) => {
                let result = match *section.get_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or_else(|| ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                };
                if let Some(empty) = section.get().as_table().and_then(|x| Some(x.is_empty())) {
                    if empty {
                        section.remove();
                    }
                }
                result
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(format_parse_error(parser))
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

fn format_parse_error(mut parser: toml::Parser) -> Option<ManifestError> {
    match parser.errors.pop() {
        Some(error) => {
            let (loline, locol) = parser.to_linecol(error.lo);
            let (hiline, hicol) = parser.to_linecol(error.hi);
            Some(ManifestError::ParseError(error.desc, loline, locol, hiline, hicol))
        },
        None => None
    }
}

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

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let clone = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
        assert_eq!(manifest, clone);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }
}
<commit_msg>Report first TOML parser error instead of last one<commit_after>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use toml;

use dependency::Dependency;

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
        ParseError(error: String, loline: usize, locol: usize, hiline: usize, hicol: usize) {
            description("parse error")
            display("{}:{}{} {}",
                loline + 1, locol + 1,
                if loline != hiline || locol != hicol {
                    format!("-{}:{}", hiline + 1,
                            hicol + 1)
                } else {
                    "".to_string()
                },
                error)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, Clone, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<(), Box<Error>> {
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));

        let new_contents = format!("[{}]\n{}{}",
                                   proj_header,
                                   proj_data,
                                   toml::Value::Table(toml));
        let new_contents_bytes = new_contents.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        try!(file.set_len(new_contents_bytes.len() as u64));
        file.write_all(new_contents_bytes).map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             dep: &Dependency)
                             -> Result<(), ManifestError> {
        let (ref name, ref data) = dep.to_toml();
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert_with(|| toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    ///     assert!(manifest.data.is_empty());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(mut section) => {
                let result = match *section.get_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or_else(|| ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                };
                if let Some(empty) = section.get().as_table().and_then(|x| Some(x.is_empty())) {
                    if empty {
                        section.remove();
                    }
                }
                result
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(format_parse_error(parser))
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

fn format_parse_error(mut parser: toml::Parser) -> Option<ManifestError> {
    parser.errors.pop().map(|error| {
        let (loline, locol) = parser.to_linecol(error.lo);
        let (hiline, hicol) = parser.to_linecol(error.hi);
        ManifestError::ParseError(error.desc.clone(), loline, locol, hiline, hicol)
    })
}

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

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let clone = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
        assert_eq!(manifest, clone);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }
}
<|endoftext|>


<commit_before>extern crate sha1;

use bencode;
use bencode::{Bencode, FromBencode};
use bencode::util::ByteString;
use std::fs::File;
use std::io::Read;

use decoder;

#[derive(PartialEq, Debug)]
pub struct Metainfo {
    pub announce: String,
    pub info: Info,
    pub info_hash: Vec<u8>,
    pub created_by: String,
}

impl FromBencode for Metainfo {
    type Err = decoder::Error;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Metainfo, decoder::Error> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let info_bytes = get_field_as_bencoded_bytes!(m, "info");
                let info_hash = calculate_sha1(&info_bytes);

                let metainfo = Metainfo{
                    announce: get_field!(m, "announce"),
                    info: get_field!(m, "info"),
                    info_hash: info_hash,
                    created_by: get_field_with_default!(m, "created by", "".to_string()),
                };
                Ok(metainfo)
            }
            _ => Err(decoder::Error::NotADict)
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct Info {
    pub piece_length: u32,
    pub pieces: Vec<Vec<u8>>,
    pub name: String,
    pub length: u32,
}

impl FromBencode for Info {
    type Err = decoder::Error;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Info, decoder::Error> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let pieces_bytes: Vec<u8> = get_field_as_bytes!(m, "pieces");
                let pieces: Vec<Vec<u8>> = pieces_bytes.chunks(20).map(|v| v.to_owned()).collect();

                let info = Info {
                    piece_length: get_field!(m, "piece length"),
                    pieces: pieces,
                    name: get_field!(m, "name"),
                    length: get_field!(m, "length"),
                };
                Ok(info)
            }
            _ => Err(decoder::Error::NotADict)
        }
    }
}

pub fn parse(filename: &str) -> Result<Metainfo, decoder::Error> {
    // read the torrent file into a byte vector
    let mut f = try!(File::open(filename));
    let mut v = Vec::new();
    try!(f.read_to_end(&mut v));

    // decode the byte vector into a struct
    let bencode = try!(bencode::from_vec(v));
    let result = try!(FromBencode::from_bencode(&bencode));

    Ok(result)
}

fn calculate_sha1(input: &[u8]) -> Vec<u8> {
    let mut hasher = sha1::Sha1::new();
    hasher.update(input);
    hasher.digest()
}
<commit_msg>Added type alias for Sha1 hashes.<commit_after>extern crate sha1;

use bencode;
use bencode::{Bencode, FromBencode};
use bencode::util::ByteString;
use std::fs::File;
use std::io::Read;

use decoder;

#[derive(PartialEq, Debug)]
pub struct Metainfo {
    pub announce: String,
    pub info: Info,
    pub info_hash: Vec<u8>,
    pub created_by: String,
}

impl FromBencode for Metainfo {
    type Err = decoder::Error;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Metainfo, decoder::Error> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let info_bytes = get_field_as_bencoded_bytes!(m, "info");
                let info_hash = calculate_sha1(&info_bytes);

                let metainfo = Metainfo{
                    announce: get_field!(m, "announce"),
                    info: get_field!(m, "info"),
                    info_hash: info_hash,
                    created_by: get_field_with_default!(m, "created by", "".to_string()),
                };
                Ok(metainfo)
            }
            _ => Err(decoder::Error::NotADict)
        }
    }
}

pub type Sha1 = Vec<u8>;

#[derive(PartialEq, Debug)]
pub struct Info {
    pub piece_length: u32,
    pub pieces: Vec<Sha1>,
    pub name: String,
    pub length: u32,
}

impl FromBencode for Info {
    type Err = decoder::Error;

    fn from_bencode(bencode: &bencode::Bencode) -> Result<Info, decoder::Error> {
        match bencode {
            &Bencode::Dict(ref m) => {
                let pieces_bytes: Vec<u8> = get_field_as_bytes!(m, "pieces");
                let pieces: Vec<Vec<u8>> = pieces_bytes.chunks(20).map(|v| v.to_owned()).collect();

                let info = Info {
                    piece_length: get_field!(m, "piece length"),
                    pieces: pieces,
                    name: get_field!(m, "name"),
                    length: get_field!(m, "length"),
                };
                Ok(info)
            }
            _ => Err(decoder::Error::NotADict)
        }
    }
}

pub fn parse(filename: &str) -> Result<Metainfo, decoder::Error> {
    // read the torrent file into a byte vector
    let mut f = try!(File::open(filename));
    let mut v = Vec::new();
    try!(f.read_to_end(&mut v));

    // decode the byte vector into a struct
    let bencode = try!(bencode::from_vec(v));
    let result = try!(FromBencode::from_bencode(&bencode));

    Ok(result)
}

fn calculate_sha1(input: &[u8]) -> Sha1 {
    let mut hasher = sha1::Sha1::new();
    hasher.update(input);
    hasher.digest()
}
<|endoftext|>


<commit_before>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => unimplemented!(),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Line records appear ordered by their section offset. This may or may not correspond to the
    /// same ordering when these offsets are converted to `Rva`. Therefore, if a monotonic order by
    /// `Rva` is required, the lines have to be sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all line records starting from a given section offset.
    ///
    /// Line records are returned grouped by the source file. They are not guaranteed to be ordered
    /// by source code offset.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<commit_msg>Update invalid comment on line ordering assumptions<commit_after>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => unimplemented!(),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all line records starting from a given section offset.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<|endoftext|>


<commit_before>use string::String;

use net::defs::{HwAddr, Ipv4Addr};

// XXX: Should this be in net::defs ?
/// IPv4 configuration of an interface
pub struct V4Configuration {
    /// Main IPv4 address
    pub ipv4: Ipv4Addr,
    /// Subnet mask
    pub ipv4_mask: Ipv4Addr,
    /// Gateway IPv4 address
    pub ipv4_gateway: Ipv4Addr,
}

/// A network interface
pub struct Interface {
    name: String,
    hw_addr: HwAddr,
    conf: V4Configuration,
}

impl Interface {
    /// Creates a new network interface
    pub fn new() -> Self {
        Interface {
            name: String::new(),
            hw_addr: HwAddr::empty(),
            conf: V4Configuration {
                ipv4: Ipv4Addr::new(0, 0, 0, 0),
                ipv4_mask: Ipv4Addr::new(0, 0, 0, 0),
                ipv4_gateway: Ipv4Addr::new(0, 0, 0, 0),
            },
        }
    }

    #[inline]
    /// Returns a reference over the name of the interface
    pub fn name_ref(&self) -> &str {
        &self.name
    }

    #[inline]
    /// Returns a reference over the hardware of the interface
    pub fn hw_addr_ref(&self) -> &HwAddr {
        &self.hw_addr
    }

    #[inline]
    /// Returns a reference over the IPv4 configuration of the interface
    pub fn v4_configuration_ref(&self) -> &V4Configuration {
        &self.conf
    }

    #[inline]
    /// Returns a mutable reference over the name of the interface
    pub fn name_mut(&mut self) -> &mut String {
        &mut self.name
    }

    #[inline]
    /// Returns a mutable reference over the hardware of the interface
    pub fn hw_addr_mut(&mut self) -> &mut HwAddr {
        &mut self.hw_addr
    }

    #[inline]
    /// Returns a mutable reference over the IPv4 configuration of the interface
    pub fn v4_configuration_mut(&mut self) -> &mut V4Configuration {
        &mut self.conf
    }
}
<commit_msg>net: Add pv_device field to Interface<commit_after>use boxed::Box;
use string::String;

use net::defs::{HwAddr, Ipv4Addr};

use hal::net::HwInterface;

// XXX: Should this be in net::defs ?
/// IPv4 configuration of an interface
pub struct V4Configuration {
    /// Main IPv4 address
    pub ipv4: Ipv4Addr,
    /// Subnet mask
    pub ipv4_mask: Ipv4Addr,
    /// Gateway IPv4 address
    pub ipv4_gateway: Ipv4Addr,
}

/// A network interface
pub struct Interface {
    name: String,
    hw_addr: HwAddr,
    conf: V4Configuration,
    pv_device: Option<Box<HwInterface>>,
}

impl Interface {
    /// Creates a new network interface
    pub fn new() -> Self {
        Interface {
            name: String::new(),
            hw_addr: HwAddr::empty(),
            conf: V4Configuration {
                ipv4: Ipv4Addr::new(0, 0, 0, 0),
                ipv4_mask: Ipv4Addr::new(0, 0, 0, 0),
                ipv4_gateway: Ipv4Addr::new(0, 0, 0, 0),
            },
            pv_device: None,
        }
    }

    #[inline]
    /// Returns a reference over the name of the interface
    pub fn name_ref(&self) -> &str {
        &self.name
    }

    #[inline]
    /// Returns a reference over the hardware of the interface
    pub fn hw_addr_ref(&self) -> &HwAddr {
        &self.hw_addr
    }

    #[inline]
    /// Returns a reference over the IPv4 configuration of the interface
    pub fn v4_configuration_ref(&self) -> &V4Configuration {
        &self.conf
    }

    #[inline]
    /// Returns a mutable reference over the name of the interface
    pub fn name_mut(&mut self) -> &mut String {
        &mut self.name
    }

    #[inline]
    /// Returns a mutable reference over the hardware of the interface
    pub fn hw_addr_mut(&mut self) -> &mut HwAddr {
        &mut self.hw_addr
    }

    #[inline]
    /// Returns a mutable reference over the IPv4 configuration of the interface
    pub fn v4_configuration_mut(&mut self) -> &mut V4Configuration {
        &mut self.conf
    }

    #[inline]
    #[doc(hidden)]
    pub fn pv_device_set(&mut self, pv: Box<HwInterface>) {
        self.pv_device = Some(pv);
    }
}
<|endoftext|>


<commit_before>mod js_obj;
mod js_type;

use std::string::String;

pub struct JsUndef;
pub struct JsNull;
pub struct JsBool(bool);
pub struct JsNum(f64);
pub struct JsSym(String);

pub struct JsStr {
    text: String,
}

impl JsStr {
    const MAX_STR_LEN: u64 = 9007199254740991; // 2^53 - 1

    fn new(s: &str) -> JsStr {
        assert!((s.len() as u64) < JsStr::MAX_STR_LEN);
        JsStr { text: s.to_string(), }
    }
}

<commit_msg>Add type alias for JsArr<commit_after>mod js_obj;
mod js_type;

use std::string::String;
use std::vec::Vec;

pub struct JsUndef;
pub struct JsNull;
pub struct JsBool(bool);
pub struct JsNum(f64);
pub struct JsSym(String);

pub struct JsStr {
    text: String,
}

impl JsStr {
    const MAX_STR_LEN: u64 = 9007199254740991; // 2^53 - 1

    fn new(s: &str) -> JsStr {
        assert!((s.len() as u64) < JsStr::MAX_STR_LEN);
        JsStr { text: s.to_string(), }
    }
}

type JsArr<JsT> = Vec<Box<JsT>>;
<|endoftext|>


<commit_before>//! Implementation of the custom `Optional` type. See `Optional`
//! docs for more information.

use rustc_serialize::{Decodable, Decoder};

/// An `Optional` can contain either `Value<T>` or `Absent`.
/// It is similar to an `Option`, but `None` will be serialized to `null`
/// while `Absent` means the value will be omitted when serialized.
///
/// An `Optional` implements the `Default` trait, it is `Absent` by default.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Optional<T> {
    Value(T),
    Absent,
}
use Optional::*;

impl<T> Optional<T> {

    /// Moves the value `v` out of the `Optional<T>` if it is `Value(v)`.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `Absent`.
    ///
    /// # Safety note
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `Absent`
    /// case explicitly.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x = Value("air");
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<&str> = Absent;
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    pub fn unwrap(self) -> T {
        match self {
            Value(val) => val,
            Absent => panic!("called `Optional::unwrap()` on a `Absent` value"),
        }
    }

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Value(x) => x,
            Absent => f()
        }
    }

    /// Maps an `Optional<T>` to `Optional<U>` by applying a function to a contained value
    ///
    /// # Examples
    ///
    /// Convert an `Optional<String>` into an `Optional<usize>`, consuming the original:
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let num_as_str: Optional<String> = Value("10".to_string());
    /// // `Optional::map` takes self *by value*, consuming `num_as_str`
    /// let num_as_int: Optional<usize> = num_as_str.map(|n| n.len());
    /// ```
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Optional<U> {
        match self {
            Value(x) => Value(f(x)),
            Absent => Absent
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Value(v) => f(v),
            Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Value(ref mut x) => Value(x),
            Absent => Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Value(ref x) => Value(x),
            Absent => Absent
        }
    }

    /// Returns `Absent` if the optional is `Absent`, otherwise calls `f` with the
    /// wrapped value and returns the result.
    ///
    /// Some languages call this operation flatmap.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// fn sq(x: u32) -> Optional<u32> { Value(x * x) }
    /// fn nope(_: u32) -> Optional<u32> { Absent }
    ///
    /// assert_eq!(Value(2).and_then(sq).and_then(sq), Value(16));
    /// assert_eq!(Value(2).and_then(sq).and_then(nope), Absent);
    /// assert_eq!(Value(2).and_then(nope).and_then(sq), Absent);
    /// assert_eq!(Absent.and_then(sq).and_then(sq), Absent);
    /// ```
    pub fn and_then<U, F: FnOnce(T) -> Optional<U>>(self, f: F) -> Optional<U> {
        match self {
            Value(x) => f(x),
            Absent => Absent,
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Absent => true,
            _ => false
        }
    }
}

impl<T> Default for Optional<T> {
    /// An optional value is absent by default.
    fn default() -> Optional<T> {
        Absent
    }
}

impl<T> Into<Option<T>> for Optional<T> {
    /// Convert Optional<T> into Option<T>
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(Some(2), x.into());
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(None, x.into());
    /// ```
    fn into(self) -> Option<T> {
        match self {
            Value(x) => Some(x),
            Absent => None,
        }
    }
}

impl<T:Decodable> Decodable for Optional<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Optional<T>, D::Error> {
        d.read_option(|d, b| {
            if b {
                Ok(Value(try!(Decodable::decode(d))))
            } else {
                Ok(Absent)
            }
        })
    }
}

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

    #[test]
    fn test_default() {
        let something: Optional<u8> = Default::default();
        assert_eq!(something, Optional::Absent);
    }

    #[test]
    fn test_default_in_struct() {
        #[derive(Default)]
        struct Foo {
            something: Optional<u8>,
            somenum: u8,
        }

        let foo1: Foo = Default::default();
        assert_eq!(foo1.something, Optional::Absent);
        assert_eq!(foo1.somenum, 0);

        let foo2 = Foo { somenum: 7, ..Default::default() };
        assert_eq!(foo2.something, Optional::Absent);
        assert_eq!(foo2.somenum, 7);
    }

}
<commit_msg>Improve docs for Optional<commit_after>//! Implementation of the custom `Optional` type. See `Optional`
//! docs for more information.

use rustc_serialize::{Decodable, Decoder};

/// An `Optional` can contain either `Value<T>` or `Absent`.
/// It is similar to an `Option`, but `None` will be serialized to `null`
/// while `Absent` means that both the key and the value will be omitted
/// when serialized.
///
/// An `Optional` implements the `Default` trait, it is `Absent` by default.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Optional<T> {
    Value(T),
    Absent,
}
use Optional::*;

impl<T> Optional<T> {

    /// Moves the value `v` out of the `Optional<T>` if it is `Value(v)`.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `Absent`.
    ///
    /// # Safety note
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `Absent`
    /// case explicitly.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x = Value("air");
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<&str> = Absent;
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    pub fn unwrap(self) -> T {
        match self {
            Value(val) => val,
            Absent => panic!("called `Optional::unwrap()` on a `Absent` value"),
        }
    }

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Value(x) => x,
            Absent => f()
        }
    }

    /// Maps an `Optional<T>` to `Optional<U>` by applying a function to a contained value
    ///
    /// # Examples
    ///
    /// Convert an `Optional<String>` into an `Optional<usize>`, consuming the original:
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let num_as_str: Optional<String> = Value("10".to_string());
    /// // `Optional::map` takes self *by value*, consuming `num_as_str`
    /// let num_as_int: Optional<usize> = num_as_str.map(|n| n.len());
    /// ```
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Optional<U> {
        match self {
            Value(x) => Value(f(x)),
            Absent => Absent
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Value(v) => f(v),
            Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Value(ref mut x) => Value(x),
            Absent => Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Value(ref x) => Value(x),
            Absent => Absent
        }
    }

    /// Returns `Absent` if the optional is `Absent`, otherwise calls `f` with the
    /// wrapped value and returns the result.
    ///
    /// Some languages call this operation flatmap.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// fn sq(x: u32) -> Optional<u32> { Value(x * x) }
    /// fn nope(_: u32) -> Optional<u32> { Absent }
    ///
    /// assert_eq!(Value(2).and_then(sq).and_then(sq), Value(16));
    /// assert_eq!(Value(2).and_then(sq).and_then(nope), Absent);
    /// assert_eq!(Value(2).and_then(nope).and_then(sq), Absent);
    /// assert_eq!(Absent.and_then(sq).and_then(sq), Absent);
    /// ```
    pub fn and_then<U, F: FnOnce(T) -> Optional<U>>(self, f: F) -> Optional<U> {
        match self {
            Value(x) => f(x),
            Absent => Absent,
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Absent => true,
            _ => false
        }
    }
}

impl<T> Default for Optional<T> {
    /// An optional value is absent by default.
    fn default() -> Optional<T> {
        Absent
    }
}

impl<T> Into<Option<T>> for Optional<T> {
    /// Convert Optional<T> into Option<T>
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::optional::Optional;
    /// # use spaceapi::optional::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(Some(2), x.into());
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(None, x.into());
    /// ```
    fn into(self) -> Option<T> {
        match self {
            Value(x) => Some(x),
            Absent => None,
        }
    }
}

impl<T:Decodable> Decodable for Optional<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Optional<T>, D::Error> {
        d.read_option(|d, b| {
            if b {
                Ok(Value(try!(Decodable::decode(d))))
            } else {
                Ok(Absent)
            }
        })
    }
}

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

    #[test]
    fn test_default() {
        let something: Optional<u8> = Default::default();
        assert_eq!(something, Optional::Absent);
    }

    #[test]
    fn test_default_in_struct() {
        #[derive(Default)]
        struct Foo {
            something: Optional<u8>,
            somenum: u8,
        }

        let foo1: Foo = Default::default();
        assert_eq!(foo1.something, Optional::Absent);
        assert_eq!(foo1.somenum, 0);

        let foo2 = Foo { somenum: 7, ..Default::default() };
        assert_eq!(foo2.something, Optional::Absent);
        assert_eq!(foo2.somenum, 7);
    }

}
<|endoftext|>