<commit_before>#![cfg(not(windows))]

extern crate libc;

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::{mem, ptr};
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use self::libc::{sigaction, SIGWINCH, SA_SIGINFO, sighandler_t, c_int, c_ushort, c_ulong};

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    start_line: u16,
    desired_rows: u16,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            start_line: start_line,
            desired_rows: desired_rows,
        }
    }

    pub fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    pub fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
        self.tty.flush();
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![0] { // SIGWINCH
                self.blank_entire_screen();
                return vec![Nothing];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: i32,
    output: File,
    output_buf: Vec<u8>,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

unsafe extern fn sigwinch_handler(signum: c_int) {
    if signum == SIGWINCH {
        get_global_tx().send([0].to_vec()).unwrap();
    }
}

fn register_sigwinch_handler() {
    unsafe {
        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = sigwinch_handler as sighandler_t;
        sigaction(SIGWINCH, &action, ptr::null_mut());
    }
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        register_sigwinch_handler();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
            output_buf: Vec::new(),
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output_buf.extend_from_slice(s);
    }

    fn writeln(&mut self, s: &str) {
        self.output_buf.extend_from_slice(s.as_bytes());
        self.output_buf.push(b'\n');
    }

    fn flush(&mut self) {
        self.output.write(&self.output_buf).unwrap();
        self.output_buf.clear();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

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

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<commit_msg>Flush tty buffer on screen close<commit_after>#![cfg(not(windows))]

extern crate libc;

use screen::Key;
use screen::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::AsRawFd;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use ansi;
use ::NEWLINE;

use std::{mem, ptr};
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use self::libc::{sigaction, SIGWINCH, SA_SIGINFO, sighandler_t, c_int, c_ushort, c_ulong};

pub struct Screen {
    tty: Terminal,
    original_stty_state: Vec<u8>,
    start_line: u16,
    desired_rows: u16,
}

impl Screen {
    pub fn open_screen(desired_rows: u16) -> Screen {
        let mut tty = Terminal::open_terminal();
        let current_stty_state = tty.stty(&["-g"]);
        tty.initialize();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        Screen {
            tty: tty,
            original_stty_state: current_stty_state,
            start_line: start_line,
            desired_rows: desired_rows,
        }
    }

    pub fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    pub fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn restore_tty(&mut self) {
        self.tty.stty(&[&String::from_utf8(self.original_stty_state.clone()).unwrap()]);
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    pub fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    pub fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
        self.tty.flush();
    }

    pub fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    pub fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    pub fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![0] { // SIGWINCH
                self.blank_entire_screen();
                return vec![Nothing];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

impl Drop for Screen {
    fn drop(&mut self) {
        self.tty.flush();
        self.restore_tty();
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: i32,
    output: File,
    output_buf: Vec<u8>,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

unsafe extern fn sigwinch_handler(signum: c_int) {
    if signum == SIGWINCH {
        get_global_tx().send([0].to_vec()).unwrap();
    }
}

fn register_sigwinch_handler() {
    unsafe {
        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = sigwinch_handler as sighandler_t;
        sigaction(SIGWINCH, &action, ptr::null_mut());
    }
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        register_sigwinch_handler();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        Terminal {
            input: rx,
            input_fd: input_fd,
            output: output_file,
            output_buf: Vec::new(),
        }
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        extern { fn dup2(src: c_int, dst: c_int) -> c_int;  }
        unsafe {
            // This is a hack until a replacement for InheritFd from old_io is available.
            dup2(self.input_fd, 0);
        }
        let mut process = match Command::new("stty")
            .args(args)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            ::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!(String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output_buf.extend_from_slice(s);
    }

    fn writeln(&mut self, s: &str) {
        self.output_buf.extend_from_slice(s.as_bytes());
        self.output_buf.push(b'\n');
    }

    fn flush(&mut self) {
        self.output.write(&self.output_buf).unwrap();
        self.output_buf.clear();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

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

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<|endoftext|>


<commit_before>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;

use crate::action;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    id: String,
    request_id: u64,
    next_response_id: u64,
}

impl Action {

    pub fn new(session_id: String, request_id: u64) -> Action {
        Action {
            id: session_id,
            request_id: request_id,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.id.clone(),
            request_id: Some(self.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

type Handler<R> = fn(&mut Action, R) -> Result<()>;

pub fn handle<R, M>(handler: Handler<R>, message: M) -> Result<()>
where
    R: action::Request,
    M: TryInto<Request<R>, Error=Box<dyn std::error::Error>>,
{
    let request = message.try_into().unwrap(); // TODO: Proper error handling.

    let mut session = Action::new(request.session_id, request.request_id);
    handler(&mut session, request.data)
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = Box<dyn std::error::Error>; // TODO: More specific error type.

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, Box<dyn std::error::Error>>
    {
        let name = match message.name {
            Some(name) => name,
            None => Err(String::from("request without an action name"))?,
        };

        let session_id = match message.session_id {
            Some(session_id) => session_id,
            None => Err(String::from("request without session id"))?,
        };

        let request_id = match message.request_id {
            Some(request_id) => request_id,
            None => Err(String::from("request without request id"))?,
        };

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        let proto = rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: proto,
        })?;

        Ok(())
    }
}
<commit_msg>Refactor order of items in the session module.<commit_after>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;

use crate::action;
pub use self::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

pub type Handler<R> = fn(&mut Action, R) -> Result<()>;

pub fn handle<R, M>(handler: Handler<R>, message: M) -> Result<()>
where
    R: action::Request,
    M: TryInto<Request<R>, Error=Box<dyn std::error::Error>>,
{
    let request = message.try_into().unwrap(); // TODO: Proper error handling.

    let mut session = Action::new(request.session_id, request.request_id);
    handler(&mut session, request.data)
}

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    id: String,
    request_id: u64,
    next_response_id: u64,
}

impl Action {

    pub fn new(session_id: String, request_id: u64) -> Action {
        Action {
            id: session_id,
            request_id: request_id,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.id.clone(),
            request_id: Some(self.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = Box<dyn std::error::Error>; // TODO: More specific error type.

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, Box<dyn std::error::Error>>
    {
        let name = match message.name {
            Some(name) => name,
            None => Err(String::from("request without an action name"))?,
        };

        let session_id = match message.session_id {
            Some(session_id) => session_id,
            None => Err(String::from("request without session id"))?,
        };

        let request_id = match message.request_id {
            Some(request_id) => request_id,
            None => Err(String::from("request without request id"))?,
        };

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        let proto = rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: proto,
        })?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate uuid;
use self::uuid::Uuid;

use std::fs;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::process::Command;

use dsl::LpProblem;
use format::lp_format::*;
use solvers::{Status, SolverTrait, WithMaxSeconds, WithNbThreads, SolverWithSolutionParsing};

#[derive(Debug, Clone)]
pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
    //params: HashMap<String, String>,
    threads: Option<u32>,
    seconds: Option<u32>,
}

impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver {
            name: "Cbc".to_string(),
            command_name: "cbc".to_string(),
            temp_solution_file: format!("{}.sol", Uuid::new_v4().to_string()),
            threads: None,
            seconds: None,
        }
    }

    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name,
            temp_solution_file: self.temp_solution_file.clone(),
            threads: None,
            seconds: None,
        }
    }

    pub fn with_temp_solution_file(&self, temp_solution_file: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name: self.command_name.clone(),
            temp_solution_file,
            threads: None,
            seconds: None,
        }
    }
}

impl SolverWithSolutionParsing for CbcSolver {
    fn read_specific_solution(&self, f: &File) -> Result<(Status, HashMap<String, f32>), String> {
        let mut vars_value: HashMap<_, _> = HashMap::new();

        let mut file = BufReader::new(f);
        let mut buffer = String::new();
        let _ = file.read_line(&mut buffer);

        let status = if let Some(status_line) = buffer.split_whitespace().next() {
            match status_line.split_whitespace().next() {
                Some("Optimal") => Status::Optimal,
                // Infeasible status is either "Infeasible" or "Integer infeasible"
                Some("Infeasible") | Some("Integer") => Status::Infeasible,
                Some("Unbounded") => Status::Unbounded,
                // "Stopped" can be "on time", "on iterations", "on difficulties" or "on ctrl-c"
                Some("Stopped") => Status::SubOptimal,
                _ => Status::NotSolved,
            }
        } else {
            return Err("Incorrect solution format".to_string());
        };
        for line in file.lines() {
            let l = line.unwrap();
            let mut result_line: Vec<_> = l.split_whitespace().collect();
            if result_line[0] == "**" {
                result_line.remove(0);
            };
            if result_line.len() == 4 {
                match result_line[2].parse::<f32>() {
                    Ok(n) => {
                        vars_value.insert(result_line[1].to_string(), n);
                    }
                    Err(e) => return Err(e.to_string()),
                }
            } else {
                return Err("Incorrect solution format".to_string());
            }
        }
        Ok((status, vars_value))
    }
}

impl WithMaxSeconds<CbcSolver> for CbcSolver {
    fn max_seconds(&self) -> Option<u32> {
        self.seconds
    }
    fn with_max_seconds(&self, seconds: u32) -> CbcSolver {
        CbcSolver {
            seconds: Some(seconds),
            ..self.clone()
        }
    }
}
impl WithNbThreads<CbcSolver> for CbcSolver {
    fn nb_threads(&self) -> Option<u32> {
        self.threads
    }
    fn with_nb_threads(&self, threads: u32) -> CbcSolver {
        CbcSolver {
            threads: Some(threads),
            ..self.clone()
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;

    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String, f32>), String> {
        let file_model = format!("{}.lp", problem.unique_name);
        problem.write_lp(&file_model).map_err(|e| e.to_string())?;

        let mut params: HashMap<String, String> = Default::default();
        let optional_params: Vec<Option<(String, u32)>> = vec![
            self.max_seconds().map(|s| ("seconds".to_owned(), s )),
            self.nb_threads().map(|t| ("threads".to_owned(), t)) ];

        for (arg, value) in optional_params.iter().flatten() {
            params.insert(arg.to_string(), value.to_string());
        }
        params.iter().for_each( |(a,b)| println!("{},{}",a,b));

        let result = Command::new(&self.command_name)
            .arg(&file_model)
            .args(params.iter().flat_map(|(k, v)| vec![k, v]))
            .arg("solve")
            .arg("solution")
            .arg(&self.temp_solution_file)
            .output()
            .map_err(|_| format!("Error running the {} solver", self.name))
            .and_then(|r| {
                if r.status.success() {
                    self.read_solution(&self.temp_solution_file)
                } else {
                    Err(r.status.to_string())
                }
            });

        let _ = fs::remove_file(file_model);
        result
    }
}
<commit_msg>Fix conflicts<commit_after>extern crate uuid;
use self::uuid::Uuid;

use std::fs;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::process::Command;

use dsl::LpProblem;
use format::lp_format::*;
use solvers::{Status, SolverTrait, WithMaxSeconds, WithNbThreads, SolverWithSolutionParsing};

#[derive(Debug, Clone)]
pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
    //params: HashMap<String, String>,
    threads: Option<u32>,
    seconds: Option<u32>,
}

impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver {
            name: "Cbc".to_string(),
            command_name: "cbc".to_string(),
            temp_solution_file: format!("{}.sol", Uuid::new_v4().to_string()),
            threads: None,
            seconds: None,
        }
    }

    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name,
            temp_solution_file: self.temp_solution_file.clone(),
            threads: None,
            seconds: None,
        }
    }

    pub fn with_temp_solution_file(&self, temp_solution_file: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name: self.command_name.clone(),
            temp_solution_file,
            threads: None,
            seconds: None,
        }
    }
}

impl SolverWithSolutionParsing for CbcSolver {
    fn read_specific_solution(&self, f: &File) -> Result<(Status, HashMap<String, f32>), String> {
        let mut vars_value: HashMap<_, _> = HashMap::new();

        let mut file = BufReader::new(f);
        let mut buffer = String::new();
        let _ = file.read_line(&mut buffer);

        let status = if let Some(status) = buffer.split_whitespace().next() {
            match status {
                "Optimal" => Status::Optimal,
                // Infeasible status is either "Infeasible" or "Integer infeasible"
                "Infeasible" | "Integer" => Status::Infeasible,
                "Unbounded" => Status::Unbounded,
                // "Stopped" can be "on time", "on iterations", "on difficulties" or "on ctrl-c"
                "Stopped" => Status::SubOptimal,
                _ => Status::NotSolved,
            }
        } else {
            return Err("Incorrect solution format".to_string());
        };
        for line in file.lines() {
            let l = line.unwrap();
            let mut result_line: Vec<_> = l.split_whitespace().collect();
            if result_line[0] == "**" {
                result_line.remove(0);
            };
            if result_line.len() == 4 {
                match result_line[2].parse::<f32>() {
                    Ok(n) => {
                        vars_value.insert(result_line[1].to_string(), n);
                    }
                    Err(e) => return Err(e.to_string()),
                }
            } else {
                return Err("Incorrect solution format".to_string());
            }
        }
        Ok((status, vars_value))
    }
}

impl WithMaxSeconds<CbcSolver> for CbcSolver {
    fn max_seconds(&self) -> Option<u32> {
        self.seconds
    }
    fn with_max_seconds(&self, seconds: u32) -> CbcSolver {
        CbcSolver {
            seconds: Some(seconds),
            ..self.clone()
        }
    }
}
impl WithNbThreads<CbcSolver> for CbcSolver {
    fn nb_threads(&self) -> Option<u32> {
        self.threads
    }
    fn with_nb_threads(&self, threads: u32) -> CbcSolver {
        CbcSolver {
            threads: Some(threads),
            ..self.clone()
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;

    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String, f32>), String> {
        let file_model = format!("{}.lp", problem.unique_name);
        problem.write_lp(&file_model).map_err(|e| e.to_string())?;

        let mut params: HashMap<String, String> = Default::default();
        let optional_params: Vec<Option<(String, u32)>> = vec![
            self.max_seconds().map(|s| ("seconds".to_owned(), s )),
            self.nb_threads().map(|t| ("threads".to_owned(), t)) ];

        for (arg, value) in optional_params.iter().flatten() {
            params.insert(arg.to_string(), value.to_string());
        }
        params.iter().for_each( |(a,b)| println!("{},{}",a,b));

        let result = Command::new(&self.command_name)
            .arg(&file_model)
            .args(params.iter().flat_map(|(k, v)| vec![k, v]))
            .arg("solve")
            .arg("solution")
            .arg(&self.temp_solution_file)
            .output()
            .map_err(|_| format!("Error running the {} solver", self.name))
            .and_then(|r| {
                if r.status.success() {
                    self.read_solution(&self.temp_solution_file)
                } else {
                    Err(r.status.to_string())
                }
            });

        let _ = fs::remove_file(file_model);
        result
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use nix::sys::ioctl;
use std::mem;
use std::io;
use std::os::unix::prelude::*;
use super::SpiModeFlags;

const SPI_IOC_MAGIC: u8 = 'k' as u8;

const SPI_IOC_NR_TRANSFER: u8 = 0;
const SPI_IOC_NR_MODE: u8 = 1;
const SPI_IOC_NR_LSB_FIRST: u8 = 2;
const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
const SPI_IOC_NR_MODE32: u8 = 5;

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
    match res {
        Ok(r) => Ok(r),
        Err(err) => Err(from_nix_error(err)),
    }
}

/// Structure that is used when performing communication
/// with the kernel.
///
/// From the kernel documentation:
///
/// ```text
/// struct spi_ioc_transfer - describes a single SPI transfer
/// @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
///   If no data is provided, zeroes are shifted out.
/// @rx_buf: Holds pointer to userspace buffer for receive data, or null.
/// @len: Length of tx and rx buffers, in bytes.
/// @speed_hz: Temporary override of the device's bitrate.
/// @bits_per_word: Temporary override of the device's wordsize.
/// @delay_usecs: If nonzero, how long to delay after the last bit transfer
///      before optionally deselecting the device before the next transfer.
/// @cs_change: True to deselect device before starting the next transfer.
///
/// This structure is mapped directly to the kernel spi_transfer structure;
/// the fields have the same meanings, except of course that the pointers
/// are in a different address space (and may be of different sizes in some
/// cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
/// Zero-initialize the structure, including currently unused fields, to
/// accomodate potential future updates.
///
/// SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
/// Pass it an array of related transfers, they'll execute together.
/// Each transfer may be half duplex (either direction) or full duplex.
///
///      struct spi_ioc_transfer mesg[4];
///      ...
///      status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
///
/// So for example one transfer might send a nine bit command (right aligned
/// in a 16-bit word), the next could read a block of 8-bit data before
/// terminating that command by temporarily deselecting the chip; the next
/// could send a different nine bit command (re-selecting the chip), and the
/// last transfer might write some register values.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct spi_ioc_transfer {
    pub tx_buf: u64,
    pub rx_buf: u64,
    pub len: u32,

    // optional overrides
    pub speed_hz: u32,
    pub delay_usecs: u16,
    pub bits_per_word: u8,
    pub cs_change: u8,
    pub pad: u32,
}

/// Representation of a spidev transfer that is shared
/// with external users
#[derive(Default)]
pub struct SpidevTransfer {
    pub tx_buf: Option<Box<[u8]>>,
    pub rx_buf: Option<Box<[u8]>>,
    len: u32,
    speed_hz: u32,
    delay_usecs: u16,
    bits_per_word: u8,
    cs_change: u8,
    pad: u32,
}

impl SpidevTransfer {
    pub fn read(length: usize) -> SpidevTransfer {
        SpidevTransfer {
            tx_buf: None,
            rx_buf: Some(vec![0u8; length].into_boxed_slice()),
            len: length as u32,
            ..Default::default()
        }
    }

    pub fn write(tx_buf: &[u8]) -> SpidevTransfer {
        let len = tx_buf.len();
        let rx_buf_vec: Vec<u8> = vec![0; len];
        let mut tx_buf_vec = Vec::with_capacity(len);
        for i in 0..len {
            tx_buf_vec.push(tx_buf[i]);
        }

        SpidevTransfer {
            tx_buf: Some(tx_buf_vec.into_boxed_slice()),
            rx_buf: Some(rx_buf_vec.into_boxed_slice()),
            len: tx_buf.len() as u32,
            ..Default::default()
        }
    }

    fn as_spi_ioc_transfer(&self) -> spi_ioc_transfer {
        spi_ioc_transfer {
            tx_buf: match self.tx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            rx_buf: match self.rx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            len: self.len,
            speed_hz: self.speed_hz,
            delay_usecs: self.delay_usecs,
            bits_per_word: self.bits_per_word,
            cs_change: self.cs_change,
            pad: self.pad,
        }
    }
}

fn spidev_ioc_read<T>(fd: RawFd, nr: u8) -> io::Result<T> {
    let size = mem::size_of::<T>();
    let op = ioctl::op_read(SPI_IOC_MAGIC, nr, size);
    from_nix_result(unsafe { ioctl::read(fd, op) })
}

fn spidev_ioc_write<T>(fd: RawFd, nr: u8, data: &T) -> io::Result<()> {
    let size = mem::size_of::<T>();
    let op = ioctl::op_write(SPI_IOC_MAGIC, nr, size);
    try!(from_nix_result(unsafe { ioctl::write(fd, op, data) }));
    Ok(())
}

pub fn get_mode(fd: RawFd) -> io::Result<u8> {
    // #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
    spidev_ioc_read::<u8>(fd, SPI_IOC_NR_MODE)
}

pub fn set_mode(fd: RawFd, mode: SpiModeFlags) -> io::Result<()> {
    // #define SPI_IOC_WR_MODE   _IOW(SPI_IOC_MAGIC, 1, __u8)
    // #define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)

    // we will always use the 8-bit mode write unless bits not in
    // the 8-bit mask are used.  This is because WR_MODE32 was not
    // added until later kernels.  This provides a reasonable story
    // for forwards and backwards compatability
    if (mode.bits & 0xFFFFFF00) != 0 {
        spidev_ioc_write::<u32>(fd, SPI_IOC_NR_MODE32, &mode.bits)
    } else {
        let bits: u8 = mode.bits as u8;
        spidev_ioc_write::<u8>(fd, SPI_IOC_NR_MODE, &bits)
    }
}

pub fn get_lsb_first(fd: RawFd) -> io::Result<bool> {
    // #define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8)
    Ok(try!(spidev_ioc_read::<u8>(fd, SPI_IOC_NR_LSB_FIRST)) != 0)
}

pub fn set_lsb_first(fd: RawFd, lsb_first: bool) -> io::Result<()> {
    // #define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8)
    let lsb_first_value: u8 = if lsb_first { 1 } else { 0 };
    spidev_ioc_write(fd, SPI_IOC_NR_LSB_FIRST, &lsb_first_value)
}

pub fn get_bits_per_word(fd: RawFd) -> io::Result<u8> {
    // #define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8)
    spidev_ioc_read::<u8>(fd, SPI_IOC_NR_BITS_PER_WORD)
}

pub fn set_bits_per_word(fd: RawFd, bits_per_word: u8) -> io::Result<()> {
    // #define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8)
    spidev_ioc_write(fd, SPI_IOC_NR_BITS_PER_WORD, &bits_per_word)
}

pub fn get_max_speed_hz(fd: RawFd) -> io::Result<u32> {
    // #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
    spidev_ioc_read::<u32>(fd, SPI_IOC_NR_MAX_SPEED_HZ)
}

pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
    // #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
    spidev_ioc_write(fd, SPI_IOC_NR_MAX_SPEED_HZ, &max_speed_hz)
}

pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
    let mut raw_transfer = transfer.as_spi_ioc_transfer();
    let op = ioctl::op_write(
            SPI_IOC_MAGIC,
            SPI_IOC_NR_TRANSFER,
            mem::size_of::<spi_ioc_transfer>());

    // The kernel will directly modify the rx_buf of the SpidevTransfer
    // rx_buf if present, so there is no need to do any additional work
    try!(from_nix_result(unsafe {
        ioctl::read_into(fd, op, &mut raw_transfer)
    }));
    Ok(())
}

pub fn transfer_multiple(fd: RawFd, transfers: &Vec<SpidevTransfer>) -> io::Result<()> {
    // create a boxed slice containing several spi_ioc_transfers
    let mut raw_transfers = transfers
        .iter()
        .map(|transfer| transfer.as_spi_ioc_transfer())
        .collect::<Vec<_>>()
        .into_boxed_slice();

    let tot_size = raw_transfers.len() * mem::size_of::<spi_ioc_transfer>();
    let op = ioctl::op_write(
        SPI_IOC_MAGIC,
        SPI_IOC_NR_TRANSFER,
        tot_size);

    // The kernel will directly modify the rx_buf of each transfer
    // so no additional work is required here
    try!(from_nix_result(unsafe {
        ioctl::read_into_ptr(fd, op, raw_transfers.as_mut_ptr())
    }));
    Ok(())
}
<commit_msg>Add #[repr(C)] to spi_ioc_transfer<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use nix::sys::ioctl;
use std::mem;
use std::io;
use std::os::unix::prelude::*;
use super::SpiModeFlags;

const SPI_IOC_MAGIC: u8 = 'k' as u8;

const SPI_IOC_NR_TRANSFER: u8 = 0;
const SPI_IOC_NR_MODE: u8 = 1;
const SPI_IOC_NR_LSB_FIRST: u8 = 2;
const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
const SPI_IOC_NR_MODE32: u8 = 5;

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
    match res {
        Ok(r) => Ok(r),
        Err(err) => Err(from_nix_error(err)),
    }
}

/// Structure that is used when performing communication
/// with the kernel.
///
/// From the kernel documentation:
///
/// ```text
/// struct spi_ioc_transfer - describes a single SPI transfer
/// @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
///   If no data is provided, zeroes are shifted out.
/// @rx_buf: Holds pointer to userspace buffer for receive data, or null.
/// @len: Length of tx and rx buffers, in bytes.
/// @speed_hz: Temporary override of the device's bitrate.
/// @bits_per_word: Temporary override of the device's wordsize.
/// @delay_usecs: If nonzero, how long to delay after the last bit transfer
///      before optionally deselecting the device before the next transfer.
/// @cs_change: True to deselect device before starting the next transfer.
///
/// This structure is mapped directly to the kernel spi_transfer structure;
/// the fields have the same meanings, except of course that the pointers
/// are in a different address space (and may be of different sizes in some
/// cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
/// Zero-initialize the structure, including currently unused fields, to
/// accomodate potential future updates.
///
/// SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
/// Pass it an array of related transfers, they'll execute together.
/// Each transfer may be half duplex (either direction) or full duplex.
///
///      struct spi_ioc_transfer mesg[4];
///      ...
///      status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
///
/// So for example one transfer might send a nine bit command (right aligned
/// in a 16-bit word), the next could read a block of 8-bit data before
/// terminating that command by temporarily deselecting the chip; the next
/// could send a different nine bit command (re-selecting the chip), and the
/// last transfer might write some register values.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
struct spi_ioc_transfer {
    pub tx_buf: u64,
    pub rx_buf: u64,
    pub len: u32,

    // optional overrides
    pub speed_hz: u32,
    pub delay_usecs: u16,
    pub bits_per_word: u8,
    pub cs_change: u8,
    pub pad: u32,
}

/// Representation of a spidev transfer that is shared
/// with external users
#[derive(Default)]
pub struct SpidevTransfer {
    pub tx_buf: Option<Box<[u8]>>,
    pub rx_buf: Option<Box<[u8]>>,
    len: u32,
    speed_hz: u32,
    delay_usecs: u16,
    bits_per_word: u8,
    cs_change: u8,
    pad: u32,
}

impl SpidevTransfer {
    pub fn read(length: usize) -> SpidevTransfer {
        SpidevTransfer {
            tx_buf: None,
            rx_buf: Some(vec![0u8; length].into_boxed_slice()),
            len: length as u32,
            ..Default::default()
        }
    }

    pub fn write(tx_buf: &[u8]) -> SpidevTransfer {
        let len = tx_buf.len();
        let rx_buf_vec: Vec<u8> = vec![0; len];
        let mut tx_buf_vec = Vec::with_capacity(len);
        for i in 0..len {
            tx_buf_vec.push(tx_buf[i]);
        }

        SpidevTransfer {
            tx_buf: Some(tx_buf_vec.into_boxed_slice()),
            rx_buf: Some(rx_buf_vec.into_boxed_slice()),
            len: tx_buf.len() as u32,
            ..Default::default()
        }
    }

    fn as_spi_ioc_transfer(&self) -> spi_ioc_transfer {
        spi_ioc_transfer {
            tx_buf: match self.tx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            rx_buf: match self.rx_buf {
                Some(ref bufbox) => bufbox.as_ptr() as u64,
                None => 0,
            },
            len: self.len,
            speed_hz: self.speed_hz,
            delay_usecs: self.delay_usecs,
            bits_per_word: self.bits_per_word,
            cs_change: self.cs_change,
            pad: self.pad,
        }
    }
}

fn spidev_ioc_read<T>(fd: RawFd, nr: u8) -> io::Result<T> {
    let size = mem::size_of::<T>();
    let op = ioctl::op_read(SPI_IOC_MAGIC, nr, size);
    from_nix_result(unsafe { ioctl::read(fd, op) })
}

fn spidev_ioc_write<T>(fd: RawFd, nr: u8, data: &T) -> io::Result<()> {
    let size = mem::size_of::<T>();
    let op = ioctl::op_write(SPI_IOC_MAGIC, nr, size);
    try!(from_nix_result(unsafe { ioctl::write(fd, op, data) }));
    Ok(())
}

pub fn get_mode(fd: RawFd) -> io::Result<u8> {
    // #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
    spidev_ioc_read::<u8>(fd, SPI_IOC_NR_MODE)
}

pub fn set_mode(fd: RawFd, mode: SpiModeFlags) -> io::Result<()> {
    // #define SPI_IOC_WR_MODE   _IOW(SPI_IOC_MAGIC, 1, __u8)
    // #define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)

    // we will always use the 8-bit mode write unless bits not in
    // the 8-bit mask are used.  This is because WR_MODE32 was not
    // added until later kernels.  This provides a reasonable story
    // for forwards and backwards compatability
    if (mode.bits & 0xFFFFFF00) != 0 {
        spidev_ioc_write::<u32>(fd, SPI_IOC_NR_MODE32, &mode.bits)
    } else {
        let bits: u8 = mode.bits as u8;
        spidev_ioc_write::<u8>(fd, SPI_IOC_NR_MODE, &bits)
    }
}

pub fn get_lsb_first(fd: RawFd) -> io::Result<bool> {
    // #define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8)
    Ok(try!(spidev_ioc_read::<u8>(fd, SPI_IOC_NR_LSB_FIRST)) != 0)
}

pub fn set_lsb_first(fd: RawFd, lsb_first: bool) -> io::Result<()> {
    // #define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8)
    let lsb_first_value: u8 = if lsb_first { 1 } else { 0 };
    spidev_ioc_write(fd, SPI_IOC_NR_LSB_FIRST, &lsb_first_value)
}

pub fn get_bits_per_word(fd: RawFd) -> io::Result<u8> {
    // #define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8)
    spidev_ioc_read::<u8>(fd, SPI_IOC_NR_BITS_PER_WORD)
}

pub fn set_bits_per_word(fd: RawFd, bits_per_word: u8) -> io::Result<()> {
    // #define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8)
    spidev_ioc_write(fd, SPI_IOC_NR_BITS_PER_WORD, &bits_per_word)
}

pub fn get_max_speed_hz(fd: RawFd) -> io::Result<u32> {
    // #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
    spidev_ioc_read::<u32>(fd, SPI_IOC_NR_MAX_SPEED_HZ)
}

pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
    // #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
    spidev_ioc_write(fd, SPI_IOC_NR_MAX_SPEED_HZ, &max_speed_hz)
}

pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
    let mut raw_transfer = transfer.as_spi_ioc_transfer();
    let op = ioctl::op_write(
            SPI_IOC_MAGIC,
            SPI_IOC_NR_TRANSFER,
            mem::size_of::<spi_ioc_transfer>());

    // The kernel will directly modify the rx_buf of the SpidevTransfer
    // rx_buf if present, so there is no need to do any additional work
    try!(from_nix_result(unsafe {
        ioctl::read_into(fd, op, &mut raw_transfer)
    }));
    Ok(())
}

pub fn transfer_multiple(fd: RawFd, transfers: &Vec<SpidevTransfer>) -> io::Result<()> {
    // create a boxed slice containing several spi_ioc_transfers
    let mut raw_transfers = transfers
        .iter()
        .map(|transfer| transfer.as_spi_ioc_transfer())
        .collect::<Vec<_>>()
        .into_boxed_slice();

    let tot_size = raw_transfers.len() * mem::size_of::<spi_ioc_transfer>();
    let op = ioctl::op_write(
        SPI_IOC_MAGIC,
        SPI_IOC_NR_TRANSFER,
        tot_size);

    // The kernel will directly modify the rx_buf of each transfer
    // so no additional work is required here
    try!(from_nix_result(unsafe {
        ioctl::read_into_ptr(fd, op, raw_transfers.as_mut_ptr())
    }));
    Ok(())
}
<|endoftext|>


<commit_before>//! Buffering wrappers for I/O traits

mod bufreader;
mod bufwriter;
mod linewriter;
mod linewritershim;

#[cfg(test)]
mod tests;

use crate::error;
use crate::fmt;
use crate::io::Error;

pub use bufreader::BufReader;
pub use bufwriter::BufWriter;
pub use linewriter::LineWriter;
use linewritershim::LineWriterShim;

/// An error returned by [`BufWriter::into_inner`] which combines an error that
/// happened while writing out the buffer, and the buffered writer object
/// which may be used to recover from the condition.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // do stuff with the stream
///
/// // we want to get our `TcpStream` back, so let's try:
///
/// let stream = match stream.into_inner() {
///     Ok(s) => s,
///     Err(e) => {
///         // Here, e is an IntoInnerError
///         panic!("An error occurred");
///     }
/// };
/// ```
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoInnerError<W>(W, Error);

impl<W> IntoInnerError<W> {
    /// Construct a new IntoInnerError
    fn new(writer: W, error: Error) -> Self {
        Self(writer, error)
    }

    /// Helper to construct a new IntoInnerError; intended to help with
    /// adapters that wrap other adapters
    fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> {
        let Self(writer, error) = self;
        IntoInnerError::new(f(writer), error)
    }

    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
    /// to fail.
    ///
    /// This error was returned when attempting to write the internal buffer.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::io::BufWriter;
    /// use std::net::TcpStream;
    ///
    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
    ///
    /// // do stuff with the stream
    ///
    /// // we want to get our `TcpStream` back, so let's try:
    ///
    /// let stream = match stream.into_inner() {
    ///     Ok(s) => s,
    ///     Err(e) => {
    ///         // Here, e is an IntoInnerError, let's log the inner error.
    ///         //
    ///         // We'll just 'log' to stdout for this example.
    ///         println!("{}", e.error());
    ///
    ///         panic!("An unexpected error occurred.");
    ///     }
    /// };
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn error(&self) -> &Error {
        &self.1
    }

    /// Returns the buffered writer instance which generated the error.
    ///
    /// The returned object can be used for error recovery, such as
    /// re-inspecting the buffer.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::io::BufWriter;
    /// use std::net::TcpStream;
    ///
    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
    ///
    /// // do stuff with the stream
    ///
    /// // we want to get our `TcpStream` back, so let's try:
    ///
    /// let stream = match stream.into_inner() {
    ///     Ok(s) => s,
    ///     Err(e) => {
    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
    ///         let buffer = e.into_inner();
    ///
    ///         // do stuff to try to recover
    ///
    ///         // afterwards, let's just return the stream
    ///         buffer.into_inner().unwrap()
    ///     }
    /// };
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn into_inner(self) -> W {
        self.0
    }

    /// Consumes the [`IntoInnerError`] and returns the error which caused the call to
    /// [`BufWriter::into_inner()`] to fail.  Unlike `error`, this can be used to
    /// obtain ownership of the underlying error.
    ///
    /// # Example
    /// ```
    /// #![feature(io_into_inner_error_parts)]
    /// use std::io::{BufWriter, ErrorKind, Write};
    ///
    /// let mut not_enough_space = [0u8; 10];
    /// let mut stream = BufWriter::new(not_enough_space.as_mut());
    /// write!(stream, "this cannot be actually written").unwrap();
    /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small");
    /// let err = into_inner_err.into_error();
    /// assert_eq!(err.kind(), ErrorKind::WriteZero);
    /// ```
    #[unstable(feature = "io_into_inner_error_parts", issue = "79704")]
    pub fn into_error(self) -> Error {
        self.1
    }

    /// Consumes the [`IntoInnerError`] and returns the error which caused the call to
    /// [`BufWriter::into_inner()`] to fail, and the underlying writer.
    ///
    /// This can be used to simply obtain ownership of the underlying error; it can also be used for
    /// advanced error recovery.
    ///
    /// # Example
    /// ```
    /// #![feature(io_into_inner_error_parts)]
    /// use std::io::{BufWriter, ErrorKind, Write};
    ///
    /// let mut not_enough_space = [0u8; 10];
    /// let mut stream = BufWriter::new(not_enough_space.as_mut());
    /// write!(stream, "this cannot be actually written").unwrap();
    /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small");
    /// let (err, recovered_writer) = into_inner_err.into_parts();
    /// assert_eq!(err.kind(), ErrorKind::WriteZero);
    /// assert_eq!(recovered_writer.buffer(), b"t be actually written");
    /// ```
    #[unstable(feature = "io_into_inner_error_parts", issue = "79704")]
    pub fn into_parts(self) -> (Error, W) {
        (self.1, self.0)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W> From<IntoInnerError<W>> for Error {
    fn from(iie: IntoInnerError<W>) -> Error {
        iie.1
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
    #[allow(deprecated, deprecated_in_future)]
    fn description(&self) -> &str {
        error::Error::description(self.error())
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W> fmt::Display for IntoInnerError<W> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.error().fmt(f)
    }
}
<commit_msg>Stabilize `into_parts()` and `into_error()`<commit_after>//! Buffering wrappers for I/O traits

mod bufreader;
mod bufwriter;
mod linewriter;
mod linewritershim;

#[cfg(test)]
mod tests;

use crate::error;
use crate::fmt;
use crate::io::Error;

pub use bufreader::BufReader;
pub use bufwriter::BufWriter;
pub use linewriter::LineWriter;
use linewritershim::LineWriterShim;

/// An error returned by [`BufWriter::into_inner`] which combines an error that
/// happened while writing out the buffer, and the buffered writer object
/// which may be used to recover from the condition.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // do stuff with the stream
///
/// // we want to get our `TcpStream` back, so let's try:
///
/// let stream = match stream.into_inner() {
///     Ok(s) => s,
///     Err(e) => {
///         // Here, e is an IntoInnerError
///         panic!("An error occurred");
///     }
/// };
/// ```
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoInnerError<W>(W, Error);

impl<W> IntoInnerError<W> {
    /// Construct a new IntoInnerError
    fn new(writer: W, error: Error) -> Self {
        Self(writer, error)
    }

    /// Helper to construct a new IntoInnerError; intended to help with
    /// adapters that wrap other adapters
    fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> {
        let Self(writer, error) = self;
        IntoInnerError::new(f(writer), error)
    }

    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
    /// to fail.
    ///
    /// This error was returned when attempting to write the internal buffer.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::io::BufWriter;
    /// use std::net::TcpStream;
    ///
    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
    ///
    /// // do stuff with the stream
    ///
    /// // we want to get our `TcpStream` back, so let's try:
    ///
    /// let stream = match stream.into_inner() {
    ///     Ok(s) => s,
    ///     Err(e) => {
    ///         // Here, e is an IntoInnerError, let's log the inner error.
    ///         //
    ///         // We'll just 'log' to stdout for this example.
    ///         println!("{}", e.error());
    ///
    ///         panic!("An unexpected error occurred.");
    ///     }
    /// };
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn error(&self) -> &Error {
        &self.1
    }

    /// Returns the buffered writer instance which generated the error.
    ///
    /// The returned object can be used for error recovery, such as
    /// re-inspecting the buffer.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use std::io::BufWriter;
    /// use std::net::TcpStream;
    ///
    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
    ///
    /// // do stuff with the stream
    ///
    /// // we want to get our `TcpStream` back, so let's try:
    ///
    /// let stream = match stream.into_inner() {
    ///     Ok(s) => s,
    ///     Err(e) => {
    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
    ///         let buffer = e.into_inner();
    ///
    ///         // do stuff to try to recover
    ///
    ///         // afterwards, let's just return the stream
    ///         buffer.into_inner().unwrap()
    ///     }
    /// };
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn into_inner(self) -> W {
        self.0
    }

    /// Consumes the [`IntoInnerError`] and returns the error which caused the call to
    /// [`BufWriter::into_inner()`] to fail.  Unlike `error`, this can be used to
    /// obtain ownership of the underlying error.
    ///
    /// # Example
    /// ```
    /// use std::io::{BufWriter, ErrorKind, Write};
    ///
    /// let mut not_enough_space = [0u8; 10];
    /// let mut stream = BufWriter::new(not_enough_space.as_mut());
    /// write!(stream, "this cannot be actually written").unwrap();
    /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small");
    /// let err = into_inner_err.into_error();
    /// assert_eq!(err.kind(), ErrorKind::WriteZero);
    /// ```
    #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")]
    pub fn into_error(self) -> Error {
        self.1
    }

    /// Consumes the [`IntoInnerError`] and returns the error which caused the call to
    /// [`BufWriter::into_inner()`] to fail, and the underlying writer.
    ///
    /// This can be used to simply obtain ownership of the underlying error; it can also be used for
    /// advanced error recovery.
    ///
    /// # Example
    /// ```
    /// use std::io::{BufWriter, ErrorKind, Write};
    ///
    /// let mut not_enough_space = [0u8; 10];
    /// let mut stream = BufWriter::new(not_enough_space.as_mut());
    /// write!(stream, "this cannot be actually written").unwrap();
    /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small");
    /// let (err, recovered_writer) = into_inner_err.into_parts();
    /// assert_eq!(err.kind(), ErrorKind::WriteZero);
    /// assert_eq!(recovered_writer.buffer(), b"t be actually written");
    /// ```
    #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")]
    pub fn into_parts(self) -> (Error, W) {
        (self.1, self.0)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W> From<IntoInnerError<W>> for Error {
    fn from(iie: IntoInnerError<W>) -> Error {
        iie.1
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
    #[allow(deprecated, deprecated_in_future)]
    fn description(&self) -> &str {
        error::Error::description(self.error())
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W> fmt::Display for IntoInnerError<W> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.error().fmt(f)
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{ULONG, DWORD, WSABUF, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_mut_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<commit_msg>fix mut ptr for windows<commit_after>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{ULONG, DWORD, WSABUF, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut wsabufs = Vec::with_capacity(buffers.len());
            for buf in buffers {
                wsabufs.push(WSABUF {
                    buf: buf.as_ptr() as *mut _,
                    len: buf.len() as ULONG
                });
            }
            let mut bytes = 0;
            let mut flags = 0;
            let ret = WSARecv(
                self.0,
                wsabufs.as_ptr() as LPWSABUF,
                wsabufs.len() as DWORD,
                &mut bytes,
                &mut flags,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let acceptor = TcpListener::bind("127.0.0.1:3444").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use net_traits::{LoadData, Metadata, ProgressMsg};
use net_traits::ProgressMsg::{Payload, Done};
use mime_classifier::MIMEClassifier;
use resource_task::{start_sending, start_sending_sniffed};

use std::borrow::ToOwned;
use std::io;
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use util::task::spawn_named;

static READ_SIZE: usize = 8192;

enum ReadStatus {
    Partial(Vec<u8>),
    EOF,
}

fn read_block(reader: &mut io::Read) -> Result<ReadStatus, String> {
    let mut buf = vec![0; READ_SIZE];
    match reader.read(buf.as_mut_slice()) {
        Ok(0) => return Ok(ReadStatus::EOF),
        Ok(n) => {
            buf.truncate(n);
            Ok(ReadStatus::Partial(buf))
        }
        Err(e) => Err(e.description().to_string()),
    }
}

fn read_all(reader: &mut io::Read, progress_chan: &Sender<ProgressMsg>)
            -> Result<(), String> {
    loop {
        match try!(read_block(reader)) {
            ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
            ReadStatus::EOF => return Ok(()),
        }
    }
}

pub fn factory(load_data: LoadData, classifier: Arc<MIMEClassifier>) {
    let url = load_data.url;
    let start_chan = load_data.consumer;
    assert!(&*url.scheme == "file");
    spawn_named("file_loader".to_owned(), move || {
        let metadata = Metadata::default(url.clone());
        let file_path: Result<PathBuf, ()> = url.to_file_path();
        match file_path {
            Ok(file_path) => {
                match File::open(&file_path) {
                    Ok(ref mut reader) => {
                        let res = read_block(reader);
                        let (res, progress_chan) = match res {
                            Ok(ReadStatus::Partial(buf)) => {
                                let progress_chan = start_sending_sniffed(start_chan, metadata,
                                                                          classifier, &buf);
                                progress_chan.send(Payload(buf)).unwrap();
                                (read_all(reader, &progress_chan), progress_chan)
                            }
                            Ok(ReadStatus::EOF) | Err(_) =>
                                (res.map(|_| ()), start_sending(start_chan, metadata)),
                        };
                        progress_chan.send(Done(res)).unwrap();
                    }
                    Err(e) => {
                        let progress_chan = start_sending(start_chan, metadata);
                        progress_chan.send(Done(Err(e.description().to_string()))).unwrap();
                    }
                }
            }
            Err(_) => {
                let progress_chan = start_sending(start_chan, metadata);
                progress_chan.send(Done(Err(url.to_string()))).unwrap();
            }
        }
    });
}
<commit_msg>Auto merge of #5631 - Ms2ger:virtual-file, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use net_traits::{LoadData, Metadata, ProgressMsg};
use net_traits::ProgressMsg::{Payload, Done};
use mime_classifier::MIMEClassifier;
use resource_task::{start_sending, start_sending_sniffed};

use std::borrow::ToOwned;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use util::task::spawn_named;

static READ_SIZE: usize = 8192;

enum ReadStatus {
    Partial(Vec<u8>),
    EOF,
}

fn read_block(reader: &mut File) -> Result<ReadStatus, String> {
    let mut buf = vec![0; READ_SIZE];
    match reader.read(buf.as_mut_slice()) {
        Ok(0) => return Ok(ReadStatus::EOF),
        Ok(n) => {
            buf.truncate(n);
            Ok(ReadStatus::Partial(buf))
        }
        Err(e) => Err(e.description().to_string()),
    }
}

fn read_all(reader: &mut File, progress_chan: &Sender<ProgressMsg>)
            -> Result<(), String> {
    loop {
        match try!(read_block(reader)) {
            ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
            ReadStatus::EOF => return Ok(()),
        }
    }
}

pub fn factory(load_data: LoadData, classifier: Arc<MIMEClassifier>) {
    let url = load_data.url;
    let start_chan = load_data.consumer;
    assert!(&*url.scheme == "file");
    spawn_named("file_loader".to_owned(), move || {
        let metadata = Metadata::default(url.clone());
        let file_path: Result<PathBuf, ()> = url.to_file_path();
        match file_path {
            Ok(file_path) => {
                match File::open(&file_path) {
                    Ok(ref mut reader) => {
                        let res = read_block(reader);
                        let (res, progress_chan) = match res {
                            Ok(ReadStatus::Partial(buf)) => {
                                let progress_chan = start_sending_sniffed(start_chan, metadata,
                                                                          classifier, &buf);
                                progress_chan.send(Payload(buf)).unwrap();
                                (read_all(reader, &progress_chan), progress_chan)
                            }
                            Ok(ReadStatus::EOF) | Err(_) =>
                                (res.map(|_| ()), start_sending(start_chan, metadata)),
                        };
                        progress_chan.send(Done(res)).unwrap();
                    }
                    Err(e) => {
                        let progress_chan = start_sending(start_chan, metadata);
                        progress_chan.send(Done(Err(e.description().to_string()))).unwrap();
                    }
                }
            }
            Err(_) => {
                let progress_chan = start_sending(start_chan, metadata);
                progress_chan.send(Done(Err(url.to_string()))).unwrap();
            }
        }
    });
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

use computed_values::font_family::FontFamily;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse};
use properties::longhands::font_family::parse_one_family;
use std::fmt;
use std::iter;
use style_traits::ToCss;
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    Local(FontFamily),
}

impl ToCss for Source {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            Source::Url(ref url) => {
                try!(dest.write_str("url(\""));
                try!(url.to_css(dest));
            },
            Source::Local(ref family) => {
                try!(dest.write_str("local(\""));
                try!(family.to_css(dest));
            },
        }
        dest.write_str("\")")
    }
}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        dest.write_str(self.url.as_str())
    }
}

/// A `@font-face` rule.
///
/// https://drafts.csswg.org/css-fonts/#font-face-rule
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontFaceRule {
    /// The font family specified with the `font-family` property declaration.
    pub family: FontFamily,
    /// The list of sources specified with the different `src` property
    /// declarations.
    pub sources: Vec<Source>,
}

impl ToCss for FontFaceRule {
    // Serialization of FontFaceRule is not specced.
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        try!(dest.write_str("@font-face { font-family: "));
        try!(self.family.to_css(dest));
        try!(dest.write_str(";"));

        if self.sources.len() > 0 {
            try!(dest.write_str(" src: "));
            let mut iter = self.sources.iter();
            try!(iter.next().unwrap().to_css(dest));
            for source in iter {
                try!(dest.write_str(", "));
                try!(source.to_css(dest));
            }
            try!(dest.write_str(";"));
        }

        dest.write_str(" }")
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
                             -> Result<FontFaceRule, ()> {
    let mut family = None;
    let mut src = None;
    let mut iter = DeclarationListParser::new(input, FontFaceRuleParser { context: context });
    while let Some(declaration) = iter.next() {
        match declaration {
            Err(range) => {
                let pos = range.start;
                let message = format!("Unsupported @font-face descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
            Ok(FontFaceDescriptorDeclaration::Family(value)) => {
                family = Some(value);
            }
            Ok(FontFaceDescriptorDeclaration::Src(value)) => {
                src = Some(value);
            }
        }
    }
    match (family, src) {
        (Some(family), Some(src)) => {
            Ok(FontFaceRule {
                family: family,
                sources: src,
            })
        }
        _ => Err(())
    }
}

/// A list of effective sources that we send over through IPC to the font cache.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

impl FontFaceRule {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources.iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

impl iter::Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

enum FontFaceDescriptorDeclaration {
    Family(FontFamily),
    Src(Vec<Source>),
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = FontFaceDescriptorDeclaration;
}

impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
    type Declaration = FontFaceDescriptorDeclaration;

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<FontFaceDescriptorDeclaration, ()> {
        match_ignore_ascii_case! { name,
            "font-family" => {
                Ok(FontFaceDescriptorDeclaration::Family(try!(
                            parse_one_family(input))))
            },
            "src" => {
                Ok(FontFaceDescriptorDeclaration::Src(try!(input.parse_comma_separated(|input| {
                    parse_one_src(self.context, input)
                }))))
            },
            _ => Err(())
        }
    }
}

fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
    if input.try(|input| input.expect_function_matching("local")).is_ok() {
        return Ok(Source::Local(try!(input.parse_nested_block(parse_one_family))))
    }

    let url = try!(SpecifiedUrl::parse(context, input));

    // Parsing optional format()
    let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
        try!(input.parse_nested_block(|input| {
            input.parse_comma_separated(|input| {
                Ok((try!(input.expect_string())).into_owned())
            })
        }))
    } else {
        vec![]
    };

    Ok(Source::Url(UrlSource {
        url: url,
        format_hints: format_hints,
    }))
}
<commit_msg>Remove intermediate FontFaceDescriptorDeclaration enum.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

use computed_values::font_family::FontFamily;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse};
use properties::longhands::font_family::parse_one_family;
use std::fmt;
use std::iter;
use style_traits::ToCss;
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    Local(FontFamily),
}

impl ToCss for Source {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            Source::Url(ref url) => {
                try!(dest.write_str("url(\""));
                try!(url.to_css(dest));
            },
            Source::Local(ref family) => {
                try!(dest.write_str("local(\""));
                try!(family.to_css(dest));
            },
        }
        dest.write_str("\")")
    }
}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        dest.write_str(self.url.as_str())
    }
}

/// A `@font-face` rule.
///
/// https://drafts.csswg.org/css-fonts/#font-face-rule
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontFaceRule {
    /// The font family specified with the `font-family` property declaration.
    pub family: FontFamily,
    /// The list of sources specified with the different `src` property
    /// declarations.
    pub sources: Vec<Source>,
}

impl ToCss for FontFaceRule {
    // Serialization of FontFaceRule is not specced.
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        try!(dest.write_str("@font-face { font-family: "));
        try!(self.family.to_css(dest));
        try!(dest.write_str(";"));

        if self.sources.len() > 0 {
            try!(dest.write_str(" src: "));
            let mut iter = self.sources.iter();
            try!(iter.next().unwrap().to_css(dest));
            for source in iter {
                try!(dest.write_str(", "));
                try!(source.to_css(dest));
            }
            try!(dest.write_str(";"));
        }

        dest.write_str(" }")
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
                             -> Result<FontFaceRule, ()> {
    let mut rule = FontFaceRule {
        family: FontFamily::Generic(atom!("")),
        sources: Vec::new(),
    };
    {
        let parser = FontFaceRuleParser { context: context, rule: &mut rule };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(range) = declaration {
                let pos = range.start;
                let message = format!("Unsupported @font-face descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
        }
    }
    if rule.family != FontFamily::Generic(atom!("")) && !rule.sources.is_empty() {
        Ok(rule)
    } else {
        Err(())
    }
}

/// A list of effective sources that we send over through IPC to the font cache.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

impl FontFaceRule {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources.iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

impl iter::Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut FontFaceRule,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
    type Declaration = ();

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
        match_ignore_ascii_case! { name,
            "font-family" => {
                self.rule.family = parse_one_family(input)?;
            },
            "src" => {
                self.rule.sources = input.parse_comma_separated(|input| {
                    parse_one_src(self.context, input)
                })?;
            },
            _ => return Err(())
        }
        Ok(())
    }
}

fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
    if input.try(|input| input.expect_function_matching("local")).is_ok() {
        return Ok(Source::Local(try!(input.parse_nested_block(parse_one_family))))
    }

    let url = try!(SpecifiedUrl::parse(context, input));

    // Parsing optional format()
    let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
        try!(input.parse_nested_block(|input| {
            input.parse_comma_separated(|input| {
                Ok((try!(input.expect_string())).into_owned())
            })
        }))
    } else {
        vec![]
    };

    Ok(Source::Url(UrlSource {
        url: url,
        format_hints: format_hints,
    }))
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate kernel32;

use super::{Width, Height};

/// Returns the size of the terminal, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::winapi::{DWORD, HANDLE};
    use self::kernel32::{GetStdHandle, GetConsoleScreenBufferInfo};
    use self::winapi::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
    use self::winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};

    let hand: HANDLE = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc.clone(),
        dwCursorPosition: zc.clone(),
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    let success: bool = unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) != 0 };
    if success {
        let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left) as u16);
        let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top) as u16);
        Some((w, h))
    } else {
        None
    }
}
<commit_msg>Remove unused imports from windows submodule<commit_after>extern crate winapi;
extern crate kernel32;

use super::{Width, Height};

/// Returns the size of the terminal, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::winapi::HANDLE;
    use self::kernel32::{GetStdHandle, GetConsoleScreenBufferInfo};
    use self::winapi::STD_OUTPUT_HANDLE;
    use self::winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};

    let hand: HANDLE = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc.clone(),
        dwCursorPosition: zc.clone(),
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    let success: bool = unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) != 0 };
    if success {
        let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left) as u16);
        let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top) as u16);
        Some((w, h))
    } else {
        None
    }
}
<|endoftext|>