<commit_before>use regex::Regex;

use super::mailbox::Mailbox;
use super::error::{Error, ParseError, Result};

pub fn parse_authenticate_response(line: String) -> Result<String> {
    let authenticate_regex = Regex::new("^+(.*)\r\n").unwrap();

    for cap in authenticate_regex.captures_iter(line.as_str()) {
        let data = cap.at(1).unwrap_or("");
        return Ok(String::from(data));
    }

    Err(Error::Parse(ParseError::Authentication(line)))
}

pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
    let capability_regex = Regex::new(r"^\* CAPABILITY (.*)\r\n").unwrap();

    //Check Ok
    match parse_response_ok(lines.clone()) {
        Ok(_) => (),
        Err(e) => return Err(e)
    };

    for line in lines.iter() {
        if capability_regex.is_match(line) {
            let cap = capability_regex.captures(line).unwrap();
            let capabilities_str = cap.at(1).unwrap();
            return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
        }
    }

    Err(Error::Parse(ParseError::Capability(lines)))
}

pub fn parse_response_ok(lines: Vec<String>) -> Result<()> {
    match parse_response(lines) {
        Ok(_) => Ok(()),
        Err(e) => return Err(e)
    }
}

pub fn parse_response(lines: Vec<String>) -> Result<Vec<String>> {
    let regex = Regex::new(r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)").unwrap();
    let last_line = match lines.last() {
        Some(l) => l,
        None => return Err(Error::Parse(ParseError::StatusResponse(lines.clone())))
    };

    for cap in regex.captures_iter(last_line) {
        let response_type = cap.at(2).unwrap_or("");
        match response_type {
            "OK" => return Ok(lines.clone()),
            "BAD" => return Err(Error::BadResponse(lines.clone())),
            "NO" => return Err(Error::NoResponse(lines.clone())),
            _ => {}
        }
    }

    Err(Error::Parse(ParseError::StatusResponse(lines.clone())))
}

pub fn parse_select_or_examine(lines: Vec<String>) -> Result<Mailbox> {
    let exists_regex = Regex::new(r"^\* (\d+) EXISTS\r\n").unwrap();

    let recent_regex = Regex::new(r"^\* (\d+) RECENT\r\n").unwrap();

    let flags_regex = Regex::new(r"^\* FLAGS (.+)\r\n").unwrap();

    let unseen_regex = Regex::new(r"^\* OK \[UNSEEN (\d+)\](.*)\r\n").unwrap();

    let uid_validity_regex = Regex::new(r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n").unwrap();

    let uid_next_regex = Regex::new(r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n").unwrap();

    let permanent_flags_regex = Regex::new(r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n").unwrap();

    //Check Ok
    match parse_response_ok(lines.clone()) {
        Ok(_) => (),
        Err(e) => return Err(e)
    };

    let mut mailbox = Mailbox::default();

    for line in lines.iter() {
        if exists_regex.is_match(line) {
            let cap = exists_regex.captures(line).unwrap();
            mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
        } else if recent_regex.is_match(line) {
            let cap = recent_regex.captures(line).unwrap();
            mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
        } else if flags_regex.is_match(line) {
            let cap = flags_regex.captures(line).unwrap();
            mailbox.flags = cap.at(1).unwrap().to_string();
        } else if unseen_regex.is_match(line) {
            let cap = unseen_regex.captures(line).unwrap();
            mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if uid_validity_regex.is_match(line) {
            let cap = uid_validity_regex.captures(line).unwrap();
            mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if uid_next_regex.is_match(line) {
            let cap = uid_next_regex.captures(line).unwrap();
            mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if permanent_flags_regex.is_match(line) {
            let cap = permanent_flags_regex.captures(line).unwrap();
            mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
        }
    }

    Ok(mailbox)
}

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

    #[test]
    fn parse_capability_test() {
        let expected_capabilities = vec![String::from("IMAP4rev1"), String::from("STARTTLS"), String::from("AUTH=GSSAPI"), String::from("LOGINDISABLED")];
        let lines = vec![String::from("* CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
        let capabilities = parse_capability(lines).unwrap();
        assert!(capabilities == expected_capabilities, "Unexpected capabilities parse response");
    }

    #[test]
    #[should_panic]
    fn parse_capability_invalid_test() {
        let lines = vec![String::from("* JUNK IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
        parse_capability(lines).unwrap();
    }

    #[test]
    fn parse_response_test() {
        let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 OK List completed.\r\n")];
        let expected_lines = lines.clone();
        let actual_lines = parse_response(lines).unwrap();
        assert!(expected_lines == actual_lines, "Unexpected parse response");
    }

    #[test]
    #[should_panic]
    fn parse_response_invalid_test() {
        let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 BAD broken.\r\n")];
        parse_response(lines).unwrap();
    }

    #[test]
    #[should_panic]
    fn parse_response_invalid2_test() {
        let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 broken.\r\n")];
        parse_response(lines).unwrap();
    }
}
<commit_msg>Removing invalid parse test<commit_after>use regex::Regex;

use super::mailbox::Mailbox;
use super::error::{Error, ParseError, Result};

pub fn parse_authenticate_response(line: String) -> Result<String> {
    let authenticate_regex = Regex::new("^+(.*)\r\n").unwrap();

    for cap in authenticate_regex.captures_iter(line.as_str()) {
        let data = cap.at(1).unwrap_or("");
        return Ok(String::from(data));
    }

    Err(Error::Parse(ParseError::Authentication(line)))
}

pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
    let capability_regex = Regex::new(r"^\* CAPABILITY (.*)\r\n").unwrap();

    //Check Ok
    match parse_response_ok(lines.clone()) {
        Ok(_) => (),
        Err(e) => return Err(e)
    };

    for line in lines.iter() {
        if capability_regex.is_match(line) {
            let cap = capability_regex.captures(line).unwrap();
            let capabilities_str = cap.at(1).unwrap();
            return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
        }
    }

    Err(Error::Parse(ParseError::Capability(lines)))
}

pub fn parse_response_ok(lines: Vec<String>) -> Result<()> {
    match parse_response(lines) {
        Ok(_) => Ok(()),
        Err(e) => return Err(e)
    }
}

pub fn parse_response(lines: Vec<String>) -> Result<Vec<String>> {
    let regex = Regex::new(r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)").unwrap();
    let last_line = match lines.last() {
        Some(l) => l,
        None => return Err(Error::Parse(ParseError::StatusResponse(lines.clone())))
    };

    for cap in regex.captures_iter(last_line) {
        let response_type = cap.at(2).unwrap_or("");
        match response_type {
            "OK" => return Ok(lines.clone()),
            "BAD" => return Err(Error::BadResponse(lines.clone())),
            "NO" => return Err(Error::NoResponse(lines.clone())),
            _ => {}
        }
    }

    Err(Error::Parse(ParseError::StatusResponse(lines.clone())))
}

pub fn parse_select_or_examine(lines: Vec<String>) -> Result<Mailbox> {
    let exists_regex = Regex::new(r"^\* (\d+) EXISTS\r\n").unwrap();

    let recent_regex = Regex::new(r"^\* (\d+) RECENT\r\n").unwrap();

    let flags_regex = Regex::new(r"^\* FLAGS (.+)\r\n").unwrap();

    let unseen_regex = Regex::new(r"^\* OK \[UNSEEN (\d+)\](.*)\r\n").unwrap();

    let uid_validity_regex = Regex::new(r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n").unwrap();

    let uid_next_regex = Regex::new(r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n").unwrap();

    let permanent_flags_regex = Regex::new(r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n").unwrap();

    //Check Ok
    match parse_response_ok(lines.clone()) {
        Ok(_) => (),
        Err(e) => return Err(e)
    };

    let mut mailbox = Mailbox::default();

    for line in lines.iter() {
        if exists_regex.is_match(line) {
            let cap = exists_regex.captures(line).unwrap();
            mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
        } else if recent_regex.is_match(line) {
            let cap = recent_regex.captures(line).unwrap();
            mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
        } else if flags_regex.is_match(line) {
            let cap = flags_regex.captures(line).unwrap();
            mailbox.flags = cap.at(1).unwrap().to_string();
        } else if unseen_regex.is_match(line) {
            let cap = unseen_regex.captures(line).unwrap();
            mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if uid_validity_regex.is_match(line) {
            let cap = uid_validity_regex.captures(line).unwrap();
            mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if uid_next_regex.is_match(line) {
            let cap = uid_next_regex.captures(line).unwrap();
            mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
        } else if permanent_flags_regex.is_match(line) {
            let cap = permanent_flags_regex.captures(line).unwrap();
            mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
        }
    }

    Ok(mailbox)
}

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

    #[test]
    fn parse_capability_test() {
        let expected_capabilities = vec![String::from("IMAP4rev1"), String::from("STARTTLS"), String::from("AUTH=GSSAPI"), String::from("LOGINDISABLED")];
        let lines = vec![String::from("* CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
        let capabilities = parse_capability(lines).unwrap();
        assert!(capabilities == expected_capabilities, "Unexpected capabilities parse response");
    }

    #[test]
    #[should_panic]
    fn parse_capability_invalid_test() {
        let lines = vec![String::from("* JUNK IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
        parse_capability(lines).unwrap();
    }

    #[test]
    fn parse_response_test() {
        let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 OK List completed.\r\n")];
        let expected_lines = lines.clone();
        let actual_lines = parse_response(lines).unwrap();
        assert!(expected_lines == actual_lines, "Unexpected parse response");
    }

    #[test]
    #[should_panic]
    fn parse_response_invalid_test() {
        let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 BAD broken.\r\n")];
        parse_response(lines).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use libc;
use std::{mem, ptr};
use std::ffi::CString;
use std::slice::from_raw_parts;

use events::Event;

use super::{events, ffi};
use super::XConnection;

#[derive(Debug)]
enum AxisType {
    HorizontalScroll,
    VerticalScroll
}

#[derive(Debug)]
struct Axis {
    id: i32,
    device_id: i32,
    axis_number: i32,
    axis_type: AxisType
}

#[derive(Debug)]
struct AxisValue {
    device_id: i32,
    axis_number: i32,
    value: f64
}

struct InputState {
    /// Last-seen cursor position within a window in (x, y)
    /// coordinates
    cursor_pos: (f64, f64),
    /// Last-seen positions of axes, used to report delta
    /// movements when a new absolute axis value is received
    axis_values: Vec<AxisValue>
}

pub struct XInputEventHandler {
    display: Arc<XConnection>,
    window: ffi::Window,
    ic: ffi::XIC,
    axis_list: Vec<Axis>,
    current_state: InputState
}

impl XInputEventHandler {
    pub fn new(display: &Arc<XConnection>, window: ffi::Window, ic: ffi::XIC) -> XInputEventHandler {
        // query XInput support
        let mut opcode: libc::c_int = 0;
        let mut event: libc::c_int = 0;
        let mut error: libc::c_int = 0;
        let xinput_str = CString::new("XInputExtension").unwrap();

        unsafe {
            if (display.xlib.XQueryExtension)(display.display, xinput_str.as_ptr(), &mut opcode, &mut event, &mut error) == ffi::False {
                panic!("XInput not available")
            }
        }

        let mut xinput_major_ver = ffi::XI_2_Major;
        let mut xinput_minor_ver = ffi::XI_2_Minor;

        unsafe {
            if (display.xinput2.XIQueryVersion)(display.display, &mut xinput_major_ver, &mut xinput_minor_ver) != ffi::Success as libc::c_int {
                panic!("Unable to determine XInput version");
            }
        }

        // specify the XInput events we want to receive.
        // Button clicks and mouse events are handled via XInput
        // events. Key presses are still handled via plain core
        // X11 events.
        let mut mask: [libc::c_uchar; 2] = [0, 0];
        let mut input_event_mask = ffi::XIEventMask {
            deviceid: ffi::XIAllDevices,
            mask_len: mask.len() as i32,
            mask: mask.as_mut_ptr()
        };
        let events = &[
            ffi::XI_ButtonPress,
            ffi::XI_ButtonRelease,
            ffi::XI_Motion,
            ffi::XI_Enter,
            ffi::XI_Leave
        ];
        for event in events {
            ffi::XISetMask(&mut mask, *event);
        }

        unsafe {
            match (display.xinput2.XISelectEvents)(display.display, window, &mut input_event_mask, 1) {
                status if status as u8 == ffi::Success => (),
                err => panic!("Failed to select events {:?}", err)
            }
        }

        XInputEventHandler {
            display: display.clone(),
            window: window,
            ic: ic,
            axis_list: read_input_axis_info(display),
            current_state: InputState {
                cursor_pos: (0.0, 0.0),
                axis_values: Vec::new()
            }
        }
    }

    pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
        use events::Event::{KeyboardInput, ReceivedCharacter};
        use events::ElementState::{Pressed, Released};

        let mut translated_events = Vec::new();

        let state;
        if event.type_ == ffi::KeyPress {
            let raw_ev: *mut ffi::XKeyEvent = event;
            unsafe { (self.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window) };
            state = Pressed;
        } else {
            state = Released;
        }

        let mut kp_keysym = 0;

        let written = unsafe {
            use std::str;

            let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
            let raw_ev: *mut ffi::XKeyEvent = event;
            let count = (self.display.xlib.Xutf8LookupString)(self.ic, mem::transmute(raw_ev),
            mem::transmute(buffer.as_mut_ptr()),
            buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut());

            str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
        };

        for chr in written.chars() {
            translated_events.push(ReceivedCharacter(chr));
        }

        let mut keysym = unsafe {
            (self.display.xlib.XKeycodeToKeysym)(self.display.display, event.keycode as ffi::KeyCode, 0)
        };

        if (ffi::XK_KP_Space as libc::c_ulong <= keysym) && (keysym <= ffi::XK_KP_9 as libc::c_ulong) {
            keysym = kp_keysym
        };

        let vkey = events::keycode_to_element(keysym as libc::c_uint);

        translated_events.push(KeyboardInput(state, event.keycode as u8, vkey));
        translated_events
    }

    pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
        use events::Event::{MouseInput, MouseMoved, MouseWheel};
        use events::ElementState::{Pressed, Released};
        use events::MouseButton::{Left, Right, Middle};
        use events::MouseScrollDelta::{PixelDelta, LineDelta};

        match cookie.evtype {
            ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let state = if cookie.evtype == ffi::XI_ButtonPress {
                    Pressed
                } else {
                    Released
                };
                match event_data.detail as u32 {
                    ffi::Button1 => Some(MouseInput(state, Left)),
                    ffi::Button2 => Some(MouseInput(state, Middle)),
                    ffi::Button3 => Some(MouseInput(state, Right)),
                    ffi::Button4 | ffi::Button5 => {
                        if event_data.flags & ffi::XIPointerEmulated == 0 {
                            // scroll event from a traditional wheel with
                            // distinct 'clicks'
                            let delta = if event_data.detail as u32 == ffi::Button4 {
                                1.0
                            } else {
                                -1.0
                            };
                            Some(MouseWheel(LineDelta(0.0, delta)))
                        } else {
                            // emulated button event from a touch/smooth-scroll
                            // event. Ignore these events and handle scrolling
                            // via XI_Motion event handler instead
                            None
                        }
                    }
                    _ => None
                }
            },
            ffi::XI_Motion => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let axis_state = event_data.valuators;
                let mask = unsafe{ from_raw_parts(axis_state.mask, axis_state.mask_len as usize) };
                let mut axis_count = 0;

                let mut scroll_delta = (0.0, 0.0);
                for axis_id in 0..axis_state.mask_len {
                    if ffi::XIMaskIsSet(&mask, axis_id) {
                        let axis_value = unsafe{*axis_state.values.offset(axis_count)};
                        let delta = calc_scroll_deltas(event_data, axis_id, axis_value, &self.axis_list,
                                                       &mut self.current_state.axis_values);
                        scroll_delta.0 += delta.0;
                        scroll_delta.1 += delta.1;
                        axis_count += 1;
                    }
                }

                if scroll_delta.0.abs() > 0.0 || scroll_delta.1.abs() > 0.0 {
                    Some(MouseWheel(PixelDelta(scroll_delta.0 as f32, scroll_delta.1 as f32)))
                } else {
                    let new_cursor_pos = (event_data.event_x, event_data.event_y);
                    if new_cursor_pos != self.current_state.cursor_pos {
                        self.current_state.cursor_pos = new_cursor_pos;
                        Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
                    } else {
                        None
                    }
                }
            },
            ffi::XI_Enter => {
                // axis movements whilst the cursor is outside the window
                // will alter the absolute value of the axes. We only want to
                // report changes in the axis value whilst the cursor is above
                // our window however, so clear the previous axis state whenever
                // the cursor re-enters the window
                self.current_state.axis_values.clear();
                None
            },
            ffi::XI_Leave => None,
            _ => None
        }
    }
}

fn read_input_axis_info(display: &Arc<XConnection>) -> Vec<Axis> {
    let mut axis_list = Vec::new();
    let mut device_count = 0;

    // only get events from the master devices which are 'attached'
    // to the keyboard or cursor
    let devices = unsafe{
        (display.xinput2.XIQueryDevice)(display.display, ffi::XIAllMasterDevices, &mut device_count)
    };
    for i in 0..device_count {
        let device = unsafe { *(devices.offset(i as isize)) };
        for k in 0..device.num_classes {
            let class = unsafe { *(device.classes.offset(k as isize)) };
            match unsafe { (*class)._type } {
                // Note that scroll axis
                // are reported both as 'XIScrollClass' and 'XIValuatorClass'
                // axes. For the moment we only care about scrolling axes.
                ffi::XIScrollClass => {
                    let scroll_class: &ffi::XIScrollClassInfo = unsafe{mem::transmute(class)};
                    axis_list.push(Axis{
                        id: scroll_class.sourceid,
                        device_id: device.deviceid,
                        axis_number: scroll_class.number,
                        axis_type: match scroll_class.scroll_type {
                            ffi::XIScrollTypeHorizontal => AxisType::HorizontalScroll,
                            ffi::XIScrollTypeVertical => AxisType::VerticalScroll,
                            _ => { unreachable!() }
                        }
                    })
                },
                _ => {}
            }
        }
    }

    axis_list
}

/// Given an input motion event for an axis and the previous
/// state of the axes, return the horizontal/vertical
/// scroll deltas
fn calc_scroll_deltas(event: &ffi::XIDeviceEvent,
                     axis_id: i32,
                     axis_value: f64,
                     axis_list: &[Axis],
                     prev_axis_values: &mut Vec<AxisValue>) -> (f64, f64) {
    let prev_value_pos = prev_axis_values.iter().position(|prev_axis| {
        prev_axis.device_id == event.sourceid &&
            prev_axis.axis_number == axis_id
    });
    let delta = match prev_value_pos {
        Some(idx) => axis_value - prev_axis_values[idx].value,
        None => 0.0
    };

    let new_axis_value = AxisValue{
        device_id: event.sourceid,
        axis_number: axis_id,
        value: axis_value
    };

    match prev_value_pos {
        Some(idx) => prev_axis_values[idx] = new_axis_value,
        None => prev_axis_values.push(new_axis_value)
    }

    let mut scroll_delta = (0.0, 0.0);

    for axis in axis_list.iter() {
        if axis.id == event.sourceid &&
            axis.axis_number == axis_id {
                match axis.axis_type {
                    AxisType::HorizontalScroll => scroll_delta.0 = delta,
                    AxisType::VerticalScroll => scroll_delta.1 = delta
                }
            }
    }

    scroll_delta
}

<commit_msg>Report focus in/out events under X11<commit_after>use std::sync::Arc;

use libc;
use std::{mem, ptr};
use std::ffi::CString;
use std::slice::from_raw_parts;

use events::Event;

use super::{events, ffi};
use super::XConnection;

#[derive(Debug)]
enum AxisType {
    HorizontalScroll,
    VerticalScroll
}

#[derive(Debug)]
struct Axis {
    id: i32,
    device_id: i32,
    axis_number: i32,
    axis_type: AxisType
}

#[derive(Debug)]
struct AxisValue {
    device_id: i32,
    axis_number: i32,
    value: f64
}

struct InputState {
    /// Last-seen cursor position within a window in (x, y)
    /// coordinates
    cursor_pos: (f64, f64),
    /// Last-seen positions of axes, used to report delta
    /// movements when a new absolute axis value is received
    axis_values: Vec<AxisValue>
}

pub struct XInputEventHandler {
    display: Arc<XConnection>,
    window: ffi::Window,
    ic: ffi::XIC,
    axis_list: Vec<Axis>,
    current_state: InputState
}

impl XInputEventHandler {
    pub fn new(display: &Arc<XConnection>, window: ffi::Window, ic: ffi::XIC) -> XInputEventHandler {
        // query XInput support
        let mut opcode: libc::c_int = 0;
        let mut event: libc::c_int = 0;
        let mut error: libc::c_int = 0;
        let xinput_str = CString::new("XInputExtension").unwrap();

        unsafe {
            if (display.xlib.XQueryExtension)(display.display, xinput_str.as_ptr(), &mut opcode, &mut event, &mut error) == ffi::False {
                panic!("XInput not available")
            }
        }

        let mut xinput_major_ver = ffi::XI_2_Major;
        let mut xinput_minor_ver = ffi::XI_2_Minor;

        unsafe {
            if (display.xinput2.XIQueryVersion)(display.display, &mut xinput_major_ver, &mut xinput_minor_ver) != ffi::Success as libc::c_int {
                panic!("Unable to determine XInput version");
            }
        }

        // specify the XInput events we want to receive.
        // Button clicks and mouse events are handled via XInput
        // events. Key presses are still handled via plain core
        // X11 events.
        let mut mask: [libc::c_uchar; 2] = [0, 0];
        let mut input_event_mask = ffi::XIEventMask {
            deviceid: ffi::XIAllDevices,
            mask_len: mask.len() as i32,
            mask: mask.as_mut_ptr()
        };
        let events = &[
            ffi::XI_ButtonPress,
            ffi::XI_ButtonRelease,
            ffi::XI_Motion,
            ffi::XI_Enter,
            ffi::XI_Leave,
            ffi::XI_FocusIn,
            ffi::XI_FocusOut
        ];
        for event in events {
            ffi::XISetMask(&mut mask, *event);
        }

        unsafe {
            match (display.xinput2.XISelectEvents)(display.display, window, &mut input_event_mask, 1) {
                status if status as u8 == ffi::Success => (),
                err => panic!("Failed to select events {:?}", err)
            }
        }

        XInputEventHandler {
            display: display.clone(),
            window: window,
            ic: ic,
            axis_list: read_input_axis_info(display),
            current_state: InputState {
                cursor_pos: (0.0, 0.0),
                axis_values: Vec::new()
            }
        }
    }

    pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
        use events::Event::{KeyboardInput, ReceivedCharacter};
        use events::ElementState::{Pressed, Released};

        let mut translated_events = Vec::new();

        let state;
        if event.type_ == ffi::KeyPress {
            let raw_ev: *mut ffi::XKeyEvent = event;
            unsafe { (self.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window) };
            state = Pressed;
        } else {
            state = Released;
        }

        let mut kp_keysym = 0;

        let written = unsafe {
            use std::str;

            let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
            let raw_ev: *mut ffi::XKeyEvent = event;
            let count = (self.display.xlib.Xutf8LookupString)(self.ic, mem::transmute(raw_ev),
            mem::transmute(buffer.as_mut_ptr()),
            buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut());

            str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
        };

        for chr in written.chars() {
            translated_events.push(ReceivedCharacter(chr));
        }

        let mut keysym = unsafe {
            (self.display.xlib.XKeycodeToKeysym)(self.display.display, event.keycode as ffi::KeyCode, 0)
        };

        if (ffi::XK_KP_Space as libc::c_ulong <= keysym) && (keysym <= ffi::XK_KP_9 as libc::c_ulong) {
            keysym = kp_keysym
        };

        let vkey = events::keycode_to_element(keysym as libc::c_uint);

        translated_events.push(KeyboardInput(state, event.keycode as u8, vkey));
        translated_events
    }

    pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
        use events::Event::{Focused, MouseInput, MouseMoved, MouseWheel};
        use events::ElementState::{Pressed, Released};
        use events::MouseButton::{Left, Right, Middle};
        use events::MouseScrollDelta::{PixelDelta, LineDelta};

        match cookie.evtype {
            ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let state = if cookie.evtype == ffi::XI_ButtonPress {
                    Pressed
                } else {
                    Released
                };
                match event_data.detail as u32 {
                    ffi::Button1 => Some(MouseInput(state, Left)),
                    ffi::Button2 => Some(MouseInput(state, Middle)),
                    ffi::Button3 => Some(MouseInput(state, Right)),
                    ffi::Button4 | ffi::Button5 => {
                        if event_data.flags & ffi::XIPointerEmulated == 0 {
                            // scroll event from a traditional wheel with
                            // distinct 'clicks'
                            let delta = if event_data.detail as u32 == ffi::Button4 {
                                1.0
                            } else {
                                -1.0
                            };
                            Some(MouseWheel(LineDelta(0.0, delta)))
                        } else {
                            // emulated button event from a touch/smooth-scroll
                            // event. Ignore these events and handle scrolling
                            // via XI_Motion event handler instead
                            None
                        }
                    }
                    _ => None
                }
            },
            ffi::XI_Motion => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let axis_state = event_data.valuators;
                let mask = unsafe{ from_raw_parts(axis_state.mask, axis_state.mask_len as usize) };
                let mut axis_count = 0;

                let mut scroll_delta = (0.0, 0.0);
                for axis_id in 0..axis_state.mask_len {
                    if ffi::XIMaskIsSet(&mask, axis_id) {
                        let axis_value = unsafe{*axis_state.values.offset(axis_count)};
                        let delta = calc_scroll_deltas(event_data, axis_id, axis_value, &self.axis_list,
                                                       &mut self.current_state.axis_values);
                        scroll_delta.0 += delta.0;
                        scroll_delta.1 += delta.1;
                        axis_count += 1;
                    }
                }

                if scroll_delta.0.abs() > 0.0 || scroll_delta.1.abs() > 0.0 {
                    Some(MouseWheel(PixelDelta(scroll_delta.0 as f32, scroll_delta.1 as f32)))
                } else {
                    let new_cursor_pos = (event_data.event_x, event_data.event_y);
                    if new_cursor_pos != self.current_state.cursor_pos {
                        self.current_state.cursor_pos = new_cursor_pos;
                        Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
                    } else {
                        None
                    }
                }
            },
            ffi::XI_Enter => {
                // axis movements whilst the cursor is outside the window
                // will alter the absolute value of the axes. We only want to
                // report changes in the axis value whilst the cursor is above
                // our window however, so clear the previous axis state whenever
                // the cursor re-enters the window
                self.current_state.axis_values.clear();
                None
            },
            ffi::XI_Leave => None,
            ffi::XI_FocusIn => Some(Focused(true)),
            ffi::XI_FocusOut => Some(Focused(false)),
            _ => None
        }
    }
}

fn read_input_axis_info(display: &Arc<XConnection>) -> Vec<Axis> {
    let mut axis_list = Vec::new();
    let mut device_count = 0;

    // only get events from the master devices which are 'attached'
    // to the keyboard or cursor
    let devices = unsafe{
        (display.xinput2.XIQueryDevice)(display.display, ffi::XIAllMasterDevices, &mut device_count)
    };
    for i in 0..device_count {
        let device = unsafe { *(devices.offset(i as isize)) };
        for k in 0..device.num_classes {
            let class = unsafe { *(device.classes.offset(k as isize)) };
            match unsafe { (*class)._type } {
                // Note that scroll axis
                // are reported both as 'XIScrollClass' and 'XIValuatorClass'
                // axes. For the moment we only care about scrolling axes.
                ffi::XIScrollClass => {
                    let scroll_class: &ffi::XIScrollClassInfo = unsafe{mem::transmute(class)};
                    axis_list.push(Axis{
                        id: scroll_class.sourceid,
                        device_id: device.deviceid,
                        axis_number: scroll_class.number,
                        axis_type: match scroll_class.scroll_type {
                            ffi::XIScrollTypeHorizontal => AxisType::HorizontalScroll,
                            ffi::XIScrollTypeVertical => AxisType::VerticalScroll,
                            _ => { unreachable!() }
                        }
                    })
                },
                _ => {}
            }
        }
    }

    axis_list
}

/// Given an input motion event for an axis and the previous
/// state of the axes, return the horizontal/vertical
/// scroll deltas
fn calc_scroll_deltas(event: &ffi::XIDeviceEvent,
                     axis_id: i32,
                     axis_value: f64,
                     axis_list: &[Axis],
                     prev_axis_values: &mut Vec<AxisValue>) -> (f64, f64) {
    let prev_value_pos = prev_axis_values.iter().position(|prev_axis| {
        prev_axis.device_id == event.sourceid &&
            prev_axis.axis_number == axis_id
    });
    let delta = match prev_value_pos {
        Some(idx) => axis_value - prev_axis_values[idx].value,
        None => 0.0
    };

    let new_axis_value = AxisValue{
        device_id: event.sourceid,
        axis_number: axis_id,
        value: axis_value
    };

    match prev_value_pos {
        Some(idx) => prev_axis_values[idx] = new_axis_value,
        None => prev_axis_values.push(new_axis_value)
    }

    let mut scroll_delta = (0.0, 0.0);

    for axis in axis_list.iter() {
        if axis.id == event.sourceid &&
            axis.axis_number == axis_id {
                match axis.axis_type {
                    AxisType::HorizontalScroll => scroll_delta.0 = delta,
                    AxisType::VerticalScroll => scroll_delta.1 = delta
                }
            }
    }

    scroll_delta
}

<|endoftext|>


<commit_before>#![feature(collections, core, io, path, env)]

extern crate "git2-curl" as git2_curl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate cargo;
extern crate env_logger;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::old_io::fs::{self, PathExtensions};
use std::old_io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use std::old_io;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match &flags.arg_command[] {
        "" | "help" if flags.arg_args.len() == 0 => {
            config.shell().set_verbose(true);
            let args = &["foo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], &flags.arg_args[0][]),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, "foo".to_string());

    macro_rules! cmd{ ($name:ident) => (
        if command == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&command, &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    match list_commands().iter()
                            // doing it this way (instead of just .min_by(|c|
                            // c.lev_distance(cmd))) allows us to only make
                            // suggestions that have an edit distance of
                            // 3 or less
                            .map(|c| (lev_distance(&c, cmd), c))
                            .filter(|&(d, _): &(usize, &String)| d < 4)
                            .min_by(|&(d, _)| d) {
        Some((_, c)) => {
            Some(c.to_string())
        },
        None => None
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    let status = Command::new(command)
                         .args(args)
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as i32), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(&msg, i as i32), shell)
        }
        Err(old_io::IoError{kind, ..}) if kind == old_io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                &format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(env::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(old_io::FileStat{ kind: old_io::FileType::RegularFile, perm, ..}) =>
            perm.contains(old_io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Strip first unused argument when passing to subcommand<commit_after>#![feature(collections, core, io, path, env)]

extern crate "git2-curl" as git2_curl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate cargo;
extern crate env_logger;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::old_io::fs::{self, PathExtensions};
use std::old_io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use std::old_io;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match &flags.arg_command[] {
        "" | "help" if flags.arg_args.len() == 0 => {
            config.shell().set_verbose(true);
            let args = &["foo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], &flags.arg_args[0][]),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, "foo".to_string());

    macro_rules! cmd{ ($name:ident) => (
        if command == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&command, &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    match list_commands().iter()
                            // doing it this way (instead of just .min_by(|c|
                            // c.lev_distance(cmd))) allows us to only make
                            // suggestions that have an edit distance of
                            // 3 or less
                            .map(|c| (lev_distance(&c, cmd), c))
                            .filter(|&(d, _): &(usize, &String)| d < 4)
                            .min_by(|&(d, _)| d) {
        Some((_, c)) => {
            Some(c.to_string())
        },
        None => None
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    let status = Command::new(command)
                         .args(&args[1..])
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as i32), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(&msg, i as i32), shell)
        }
        Err(old_io::IoError{kind, ..}) if kind == old_io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                &format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(env::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(old_io::FileStat{ kind: old_io::FileType::RegularFile, perm, ..}) =>
            perm.contains(old_io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 Johannes Köster, Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment and distance computing algorithms.

use utils::TextSlice;

pub mod pairwise;
pub mod distance;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins,
}

/// An alignment, consisting of a score, a start in sequence y, a start in sequence x, the length
/// of sequence x and its edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub yend: usize,
    pub xend: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>,
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}",
                                    k,
                                    match op {
                                        AlignmentOperation::Match => "=",
                                        AlignmentOperation::Subst => "X",
                                        AlignmentOperation::Del => "D",
                                        AlignmentOperation::Ins => "I",
                                    }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst ||
             op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {
            "H"
        } else {
            "S"
        };

        let mut cigar = String::new();

        if self.operations.is_empty() {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        } else {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    ///
    /// # Example
    ///
    /// ```
    /// use bio::alignment::pairwise::*;
    ///
    /// let x = b"CCGTCCGGCAA";
    /// let y = b"AAAAACCGTTGACGCAA";
    /// let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
    ///
    /// // ------CCGTCCGGCAA
    /// //       |  |   ||||
    /// // AAAAACCGTTGACGCAA
    /// let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, &score);
    /// let alignment = aligner.semiglobal(x, y);
    /// println!("Semiglobal: \n{}\n", alignment.pretty(x, y));
    ///
    /// // -----CCGTCCGGCAA-
    /// //      ||||
    /// // AAAAACCGTTGACGCAA
    /// let alignment = aligner.local(x, y);
    /// println!("Local: \n{}\n", alignment.pretty(x, y));
    ///
    /// // ------CCGTCCGGCAA
    /// //       |  |   ||||
    /// // AAAAACCGTTGACGCAA
    /// let alignment = aligner.global(x, y);
    /// println!("Global: \n{}\n", alignment.pretty(x, y));
    /// ```
    pub fn pretty(&self, x: TextSlice, y: TextSlice) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i: usize = self.xstart;
            let mut y_i: usize = self.ystart;

            // Add '-' before aligned subsequences and un-aligned 5' substrings of sequences.
            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            } else {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            }
            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            // Process the alignment.
            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    }
                }
            }

            // Add un-aligned 3' substrings of sequences.
            for &item in x.iter().skip(x_i) {
                x_pretty.push_str(&String::from_utf8_lossy(&[item]));
            }
            for &item in y.iter().skip(y_i) {
                y_pretty.push_str(&String::from_utf8_lossy(&[item]));
            }

            // Add trailing '-'.
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment {
            score: 5,
            xstart: 3,
            ystart: 0,
            xend: 10,
            yend: 10,
            xlen: 10,
            operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del],
        };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<commit_msg>update documentation of Alignment struct<commit_after>// Copyright 2014-2015 Johannes Köster, Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment and distance computing algorithms.

use utils::TextSlice;

pub mod pairwise;
pub mod distance;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins,
}

/// An alignment, consisting of a score, the start and end position of the alignment on
/// sequence x and sequence y, the length of sequence x,
/// and the alignment edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub yend: usize,
    pub xend: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>,
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}",
                                    k,
                                    match op {
                                        AlignmentOperation::Match => "=",
                                        AlignmentOperation::Subst => "X",
                                        AlignmentOperation::Del => "D",
                                        AlignmentOperation::Ins => "I",
                                    }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst ||
             op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {
            "H"
        } else {
            "S"
        };

        let mut cigar = String::new();

        if self.operations.is_empty() {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        } else {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    ///
    /// # Example
    ///
    /// ```
    /// use bio::alignment::pairwise::*;
    ///
    /// let x = b"CCGTCCGGCAA";
    /// let y = b"AAAAACCGTTGACGCAA";
    /// let score = |a: u8, b: u8| if a == b {1i32} else {-1i32};
    ///
    /// // ------CCGTCCGGCAA
    /// //       |  |   ||||
    /// // AAAAACCGTTGACGCAA
    /// let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, &score);
    /// let alignment = aligner.semiglobal(x, y);
    /// println!("Semiglobal: \n{}\n", alignment.pretty(x, y));
    ///
    /// // -----CCGTCCGGCAA-
    /// //      ||||
    /// // AAAAACCGTTGACGCAA
    /// let alignment = aligner.local(x, y);
    /// println!("Local: \n{}\n", alignment.pretty(x, y));
    ///
    /// // ------CCGTCCGGCAA
    /// //       |  |   ||||
    /// // AAAAACCGTTGACGCAA
    /// let alignment = aligner.global(x, y);
    /// println!("Global: \n{}\n", alignment.pretty(x, y));
    /// ```
    pub fn pretty(&self, x: TextSlice, y: TextSlice) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i: usize = self.xstart;
            let mut y_i: usize = self.ystart;

            // Add '-' before aligned subsequences and un-aligned 5' substrings of sequences.
            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            } else {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            }
            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            // Process the alignment.
            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    }
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    }
                }
            }

            // Add un-aligned 3' substrings of sequences.
            for &item in x.iter().skip(x_i) {
                x_pretty.push_str(&String::from_utf8_lossy(&[item]));
            }
            for &item in y.iter().skip(y_i) {
                y_pretty.push_str(&String::from_utf8_lossy(&[item]));
            }

            // Add trailing '-'.
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment {
            score: 5,
            xstart: 3,
            ystart: 0,
            xend: 10,
            yend: 10,
            xlen: 10,
            operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del],
        };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<|endoftext|>


<commit_before>mod path;
mod item;
mod content;

use hyper::method::Method;
use serde_json;
use ::connection::Connection;
use ::odata::Parameters;
use ::api::MultiOption;
use ::Result;

pub use self::path::Path;
pub use self::item::{Item, Kind};
pub use self::content::Content;

/// Items Entities
pub struct Items {
	conn: Connection,
	meta: bool,
}

impl Items {
	pub fn new(conn: Connection) -> Self {
		Items {
			conn: conn,
			meta: false,
		}
	}

	pub fn include_meta(&mut self, include: bool) {
		self.meta = include;
	}

	pub fn stat(&self, path: Path, parameters: Option<Parameters>) -> Result<MultiOption<Item>> {
		self.query_items(path.entity_and_parameters(None, parameters))
	}

	pub fn list(&self, path: Path, parameters: Option<Parameters>) -> Result<MultiOption<Item>> {
		match self.stat(path, None) {
			Ok(MultiOption::One(item)) => {
				self.query_items(Path::Id(item.id).entity_and_parameters(Some("/Children"), parameters))
			},
			Ok(other) => Ok(other),
			Err(err) => err.result()
		}
	}

	pub fn download<T>(&self, id: T) -> Result<Content> where T: Into<String> {
		Content::open_for_read(self.conn.clone(), id.into())
	}

	fn query_items(&self, uri: String) -> Result<MultiOption<Item>> {
		match self.conn.query_string(Method::Get, uri, None, None) {
			Ok(json) => Item::from_value(serde_json::from_str(&json).unwrap(), self.meta),
			Err(err) => err.result()
		}
	}
}
<commit_msg>Allow to identify item for download by Path<commit_after>mod path;
mod item;
mod content;

use hyper::method::Method;
use serde_json;
use ::connection::Connection;
use ::odata::Parameters;
use ::api::MultiOption;
use ::{Result, Error};

pub use self::path::Path;
pub use self::item::{Item, Kind};
pub use self::content::Content;

/// Items Entities
pub struct Items {
	conn: Connection,
	meta: bool,
}

impl Items {
	pub fn new(conn: Connection) -> Self {
		Items {
			conn: conn,
			meta: false,
		}
	}

	pub fn include_meta(&mut self, include: bool) {
		self.meta = include;
	}

	pub fn stat(&self, path: Path, parameters: Option<Parameters>) -> Result<MultiOption<Item>> {
		self.query_items(path.entity_and_parameters(None, parameters))
	}

	pub fn list(&self, path: Path, parameters: Option<Parameters>) -> Result<MultiOption<Item>> {
		match self.stat(path, None) {
			Ok(MultiOption::One(item)) => {
				self.query_items(Path::Id(item.id).entity_and_parameters(Some("/Children"), parameters))
			},
			Ok(other) => Ok(other),
			Err(err) => err.result()
		}
	}

	pub fn download(&self, path: Path) -> Result<Content> {
		if let Path::Id(id) = path {
			// We have the ID alredy so just start download
			Content::open_for_read(self.conn.clone(), id)
		}
		else {
			// We have a path which should be resolved to the id first
			match self.stat(path, None) {
				Ok(MultiOption::One(item)) => Content::open_for_read(self.conn.clone(), item.id),
				Ok(MultiOption::Many(_)) => Error::new("There are more than one Item on path").result(),
				Ok(MultiOption::None) => Error::new("The Item is not found").result(),
				Err(err) => err.result()
			}
		}
	}

	fn query_items(&self, uri: String) -> Result<MultiOption<Item>> {
		match self.conn.query_string(Method::Get, uri, None, None) {
			Ok(json) => Item::from_value(serde_json::from_str(&json).unwrap(), self.meta),
			Err(err) => err.result()
		}
	}
}
<|endoftext|>


<commit_before>use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use syntax::ast;

use crate::transform::{MirPass, MirSource};
use rustc::mir::{self, Body, BodyAndCache, Local, Location};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;

use crate::dataflow::generic::{Analysis, Results, ResultsCursor};
use crate::dataflow::move_paths::{HasMoveData, MoveData};
use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
use crate::dataflow::IndirectlyMutableLocals;
use crate::dataflow::MoveDataParamEnv;
use crate::dataflow::{do_dataflow, DebugFormatted};
use crate::dataflow::{
    DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
};

pub struct SanityCheck;

impl<'tcx> MirPass<'tcx> for SanityCheck {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        use crate::dataflow::has_rustc_mir_with;

        let def_id = src.def_id();
        if !tcx.has_attr(def_id, sym::rustc_mir) {
            debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
            return;
        } else {
            debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
        }

        let attributes = tcx.get_attrs(def_id);
        let param_env = tcx.param_env(def_id);
        let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
        let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
        let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());

        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let _flow_indirectly_mut = do_dataflow(
            tcx,
            body,
            def_id,
            &attributes,
            &dead_unwinds,
            IndirectlyMutableLocals::new(tcx, body, param_env),
            |_, i| DebugFormatted::new(&i),
        );

        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits);
        }
        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits);
        }
        if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits);
        }
        // FIXME: Uncomment these as analyses are migrated to the new framework
        /*
        if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_indirectly_mut);
        }
        */
        if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() {
            tcx.sess.fatal("stop_after_dataflow ended compilation");
        }
    }
}

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'tcx, A>(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    _attributes: &[ast::Attribute],
    results: &Results<'tcx, A>,
) where
    A: RustcPeekAt<'tcx>,
{
    debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);

    let mut cursor = ResultsCursor::new(body, results);

    let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| {
        PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
    });

    for (bb, block_data, call) in peek_calls {
        // Look for a sequence like the following to indicate that we should be peeking at `_1`:
        //    _2 = &_1;
        //    rustc_peek(_2);
        //
        //    /* or */
        //
        //    _2 = _1;
        //    rustc_peek(_2);
        let (statement_index, peek_rval) = block_data
            .statements
            .iter()
            .enumerate()
            .filter_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval)))
            .next()
            .expect(
                "call to rustc_peek should be preceded by \
                    assignment to temporary holding its argument",
            );

        match (call.kind, peek_rval) {
            (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place))
            | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Move(place)))
            | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Copy(place))) => {
                let loc = Location { block: bb, statement_index };
                cursor.seek_before(loc);
                let state = cursor.get();
                results.analysis.peek_at(tcx, place, state, call);
            }

            _ => {
                let msg = "rustc_peek: argument expression \
                           must be either `place` or `&place`";
                tcx.sess.span_err(call.span, msg);
            }
        }
    }
}

/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the
/// RHS of the assignment.
fn value_assigned_to_local<'a, 'tcx>(
    stmt: &'a mir::Statement<'tcx>,
    local: Local,
) -> Option<&'a mir::Rvalue<'tcx>> {
    if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
        if let Some(l) = place.as_local() {
            if local == l {
                return Some(&*rvalue);
            }
        }
    }

    None
}

#[derive(Clone, Copy, Debug)]
enum PeekCallKind {
    ByVal,
    ByRef,
}

impl PeekCallKind {
    fn from_arg_ty(arg: Ty<'_>) -> Self {
        match arg.kind {
            ty::Ref(_, _, _) => PeekCallKind::ByRef,
            _ => PeekCallKind::ByVal,
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct PeekCall {
    arg: Local,
    kind: PeekCallKind,
    span: Span,
}

impl PeekCall {
    fn from_terminator<'tcx>(
        tcx: TyCtxt<'tcx>,
        terminator: &mir::Terminator<'tcx>,
    ) -> Option<Self> {
        use mir::Operand;

        let span = terminator.source_info.span;
        if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
            &terminator.kind
        {
            if let ty::FnDef(def_id, substs) = func.literal.ty.kind {
                let sig = tcx.fn_sig(def_id);
                let name = tcx.item_name(def_id);
                if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek {
                    return None;
                }

                assert_eq!(args.len(), 1);
                let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
                let arg = match &args[0] {
                    Operand::Copy(place) | Operand::Move(place) => {
                        if let Some(local) = place.as_local() {
                            local
                        } else {
                            tcx.sess.diagnostic().span_err(
                                span,
                                "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
                            );
                            return None;
                        }
                    }
                    _ => {
                        tcx.sess.diagnostic().span_err(
                            span,
                            "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
                        );
                        return None;
                    }
                };

                return Some(PeekCall { arg, kind, span });
            }
        }

        None
    }
}

pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Self::Idx>,
        call: PeekCall,
    );
}

impl<'tcx, A> RustcPeekAt<'tcx> for A
where
    A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
{
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Self::Idx>,
        call: PeekCall,
    ) {
        match self.move_data().rev_lookup.find(place.as_ref()) {
            LookupResult::Exact(peek_mpi) => {
                let bit_state = flow_state.contains(peek_mpi);
                debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
                if !bit_state {
                    tcx.sess.span_err(call.span, "rustc_peek: bit not set");
                }
            }

            LookupResult::Parent(..) => {
                tcx.sess.span_err(call.span, "rustc_peek: argument untracked");
            }
        }
    }
}

/* FIXME: Add this back once `IndirectlyMutableLocals` uses the new dataflow framework.
impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> {
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Local>,
        call: PeekCall,
    ) {
        warn!("peek_at: place={:?}", place);
        let local = if let Some(l) = place.as_local() {
            l
        } else {
            tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
            return;
        };

        if !flow_state.contains(local) {
            tcx.sess.span_err(call.span, "rustc_peek: bit not set");
        }
    }
}
*/
<commit_msg>Reenable peek test for indirect mutation analysis<commit_after>use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use syntax::ast;

use crate::transform::{MirPass, MirSource};
use rustc::mir::{self, Body, BodyAndCache, Local, Location};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;

use crate::dataflow::generic::{Analysis, Results, ResultsCursor};
use crate::dataflow::move_paths::{HasMoveData, MoveData};
use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
use crate::dataflow::MaybeMutBorrowedLocals;
use crate::dataflow::MoveDataParamEnv;
use crate::dataflow::{
    DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
};

pub struct SanityCheck;

impl<'tcx> MirPass<'tcx> for SanityCheck {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        use crate::dataflow::has_rustc_mir_with;
        let def_id = src.def_id();
        if !tcx.has_attr(def_id, sym::rustc_mir) {
            debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
            return;
        } else {
            debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
        }

        let attributes = tcx.get_attrs(def_id);
        let param_env = tcx.param_env(def_id);
        let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
        let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };

        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();
        let flow_mut_borrowed = MaybeMutBorrowedLocals::new_mut_only(tcx, body, param_env)
            .into_engine(tcx, body, def_id)
            .iterate_to_fixpoint();

        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits);
        }
        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits);
        }
        if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits);
        }
        if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() {
            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_mut_borrowed);
        }
        if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() {
            tcx.sess.fatal("stop_after_dataflow ended compilation");
        }
    }
}

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'tcx, A>(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    _attributes: &[ast::Attribute],
    results: &Results<'tcx, A>,
) where
    A: RustcPeekAt<'tcx>,
{
    debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);

    let mut cursor = ResultsCursor::new(body, results);

    let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| {
        PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
    });

    for (bb, block_data, call) in peek_calls {
        // Look for a sequence like the following to indicate that we should be peeking at `_1`:
        //    _2 = &_1;
        //    rustc_peek(_2);
        //
        //    /* or */
        //
        //    _2 = _1;
        //    rustc_peek(_2);
        let (statement_index, peek_rval) = block_data
            .statements
            .iter()
            .enumerate()
            .filter_map(|(i, stmt)| value_assigned_to_local(stmt, call.arg).map(|rval| (i, rval)))
            .next()
            .expect(
                "call to rustc_peek should be preceded by \
                    assignment to temporary holding its argument",
            );

        match (call.kind, peek_rval) {
            (PeekCallKind::ByRef, mir::Rvalue::Ref(_, _, place))
            | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Move(place)))
            | (PeekCallKind::ByVal, mir::Rvalue::Use(mir::Operand::Copy(place))) => {
                let loc = Location { block: bb, statement_index };
                cursor.seek_before(loc);
                let state = cursor.get();
                results.analysis.peek_at(tcx, place, state, call);
            }

            _ => {
                let msg = "rustc_peek: argument expression \
                           must be either `place` or `&place`";
                tcx.sess.span_err(call.span, msg);
            }
        }
    }
}

/// If `stmt` is an assignment where the LHS is the given local (with no projections), returns the
/// RHS of the assignment.
fn value_assigned_to_local<'a, 'tcx>(
    stmt: &'a mir::Statement<'tcx>,
    local: Local,
) -> Option<&'a mir::Rvalue<'tcx>> {
    if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
        if let Some(l) = place.as_local() {
            if local == l {
                return Some(&*rvalue);
            }
        }
    }

    None
}

#[derive(Clone, Copy, Debug)]
enum PeekCallKind {
    ByVal,
    ByRef,
}

impl PeekCallKind {
    fn from_arg_ty(arg: Ty<'_>) -> Self {
        match arg.kind {
            ty::Ref(_, _, _) => PeekCallKind::ByRef,
            _ => PeekCallKind::ByVal,
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct PeekCall {
    arg: Local,
    kind: PeekCallKind,
    span: Span,
}

impl PeekCall {
    fn from_terminator<'tcx>(
        tcx: TyCtxt<'tcx>,
        terminator: &mir::Terminator<'tcx>,
    ) -> Option<Self> {
        use mir::Operand;

        let span = terminator.source_info.span;
        if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
            &terminator.kind
        {
            if let ty::FnDef(def_id, substs) = func.literal.ty.kind {
                let sig = tcx.fn_sig(def_id);
                let name = tcx.item_name(def_id);
                if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek {
                    return None;
                }

                assert_eq!(args.len(), 1);
                let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
                let arg = match &args[0] {
                    Operand::Copy(place) | Operand::Move(place) => {
                        if let Some(local) = place.as_local() {
                            local
                        } else {
                            tcx.sess.diagnostic().span_err(
                                span,
                                "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
                            );
                            return None;
                        }
                    }
                    _ => {
                        tcx.sess.diagnostic().span_err(
                            span,
                            "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
                        );
                        return None;
                    }
                };

                return Some(PeekCall { arg, kind, span });
            }
        }

        None
    }
}

pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Self::Idx>,
        call: PeekCall,
    );
}

impl<'tcx, A> RustcPeekAt<'tcx> for A
where
    A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
{
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Self::Idx>,
        call: PeekCall,
    ) {
        match self.move_data().rev_lookup.find(place.as_ref()) {
            LookupResult::Exact(peek_mpi) => {
                let bit_state = flow_state.contains(peek_mpi);
                debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
                if !bit_state {
                    tcx.sess.span_err(call.span, "rustc_peek: bit not set");
                }
            }

            LookupResult::Parent(..) => {
                tcx.sess.span_err(call.span, "rustc_peek: argument untracked");
            }
        }
    }
}

impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
    fn peek_at(
        &self,
        tcx: TyCtxt<'tcx>,
        place: &mir::Place<'tcx>,
        flow_state: &BitSet<Local>,
        call: PeekCall,
    ) {
        warn!("peek_at: place={:?}", place);
        let local = if let Some(l) = place.as_local() {
            l
        } else {
            tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
            return;
        };

        if !flow_state.contains(local) {
            tcx.sess.span_err(call.span, "rustc_peek: bit not set");
        }
    }
}
<|endoftext|>


<commit_before>use rustyline;
use rustyline::line_buffer::LineBuffer;

pub struct CustomCompletion {
    commands: Vec<&'static str>,
    hinter: rustyline::hint::HistoryHinter,
}

impl CustomCompletion {
    pub fn new() -> Self {
        let commands: Vec<&str> = vec!["help", "items", "projs", "quit"];

        Self {
            commands,
            hinter: rustyline::hint::HistoryHinter {},
        }
    }
}

impl rustyline::completion::Completer for CustomCompletion {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let mut completions: Vec<String> = Vec::new();
        for command in &self.commands {
            if command.starts_with(line) {
                completions.push(command.to_string());
            }
        }

        Ok((pos, completions))
    }

    fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
        line.update(elected, start);
    }
}

impl rustyline::hint::Hinter for CustomCompletion {
    fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
        self.hinter.hint(line, pos, ctx)
    }
}

impl rustyline::validate::Validator for CustomCompletion {}

impl rustyline::Helper for CustomCompletion {}

impl rustyline::highlight::Highlighter for CustomCompletion {}

// Tests

#[cfg(test)]
use rustyline::completion::Completer;

#[cfg(test)]
fn verify_completion(input: &str, expected_completion: &str) {
    let hist = rustyline::history::History::new();
    let ctx = rustyline::Context::new(&hist);

    let completer = CustomCompletion::new();
    assert_eq!(
        completer.complete(input, 0, &ctx).unwrap(),
        (0, vec![String::from(expected_completion)])
    );
}

#[test]
fn completion_test_items() {
    // Verify that the completion for i completes to items.
    verify_completion("i", "items");
    verify_completion("ite", "items");
}

#[test]
fn completion_test_quit() {
    // Verify that the completion for q completes to quit.
    verify_completion("q", "quit");
    verify_completion("qui", "quit");
}

#[test]
fn completion_test_help() {
    // Verify that the completion for h completes to help.
    verify_completion("h", "help");
    verify_completion("he", "help");
}

#[test]
fn completion_test_projects() {
    // Verify that the completion for p completes to projs.
    verify_completion("p", "projs");
    verify_completion("pro", "projs");
}
<commit_msg>Completer: Implement new required interface for rustyline hinter<commit_after>use rustyline;
use rustyline::line_buffer::LineBuffer;

pub struct CustomCompletion {
    commands: Vec<&'static str>,
    hinter: rustyline::hint::HistoryHinter,
}

impl CustomCompletion {
    pub fn new() -> Self {
        let commands: Vec<&str> = vec!["help", "items", "projs", "quit"];

        Self {
            commands,
            hinter: rustyline::hint::HistoryHinter {},
        }
    }
}

impl rustyline::completion::Completer for CustomCompletion {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let mut completions: Vec<String> = Vec::new();
        for command in &self.commands {
            if command.starts_with(line) {
                completions.push(command.to_string());
            }
        }

        Ok((pos, completions))
    }

    fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
        line.update(elected, start);
    }
}

impl rustyline::hint::Hinter for CustomCompletion {
    type Hint = String;

    fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
        self.hinter.hint(line, pos, ctx)
    }
}

impl rustyline::validate::Validator for CustomCompletion {}

impl rustyline::Helper for CustomCompletion {}

impl rustyline::highlight::Highlighter for CustomCompletion {}

// Tests

#[cfg(test)]
use rustyline::completion::Completer;

#[cfg(test)]
fn verify_completion(input: &str, expected_completion: &str) {
    let hist = rustyline::history::History::new();
    let ctx = rustyline::Context::new(&hist);

    let completer = CustomCompletion::new();
    assert_eq!(
        completer.complete(input, 0, &ctx).unwrap(),
        (0, vec![String::from(expected_completion)])
    );
}

#[test]
fn completion_test_items() {
    // Verify that the completion for i completes to items.
    verify_completion("i", "items");
    verify_completion("ite", "items");
}

#[test]
fn completion_test_quit() {
    // Verify that the completion for q completes to quit.
    verify_completion("q", "quit");
    verify_completion("qui", "quit");
}

#[test]
fn completion_test_help() {
    // Verify that the completion for h completes to help.
    verify_completion("h", "help");
    verify_completion("he", "help");
}

#[test]
fn completion_test_projects() {
    // Verify that the completion for p completes to projs.
    verify_completion("p", "projs");
    verify_completion("pro", "projs");
}
<|endoftext|>