<commit_before>//! Windows specific definitions
use std::io::{self, Stdout, Write};
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use error;
use Result;
use super::{RawMode, RawReader, Term};

const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

fn get_win_size(handle: winapi::HANDLE) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, (1 + info.srWindow.Bottom - info.srWindow.Top) as usize),
    }
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<winapi::DWORD> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

pub type Mode = ConsoleMode;

#[derive(Clone,Copy,Debug)]
pub struct ConsoleMode {
    original_mode: winapi::DWORD,
    stdin_handle: winapi::HANDLE,
}

impl RawMode for Mode {
    /// Disable RAW mode for the terminal.
    fn disable_raw_mode(&self) -> Result<()> {
        check!(kernel32::SetConsoleMode(self.stdin_handle, self.original_mode));
        Ok(())
    }
}

/// Console input reader
pub struct ConsoleRawReader {
    handle: winapi::HANDLE,
    buf: Option<u16>,
}

impl ConsoleRawReader {
    pub fn new() -> Result<ConsoleRawReader> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(ConsoleRawReader {
            handle: handle,
            buf: None,
        })
    }
}

impl RawReader for ConsoleRawReader {
    fn next_key(&mut self, _: i32) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                debug!(target: "rustyline", "SIGWINCH");
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }
            // key_event.wRepeatCount seems to be always set to 1 (maybe because we only read one character at a time)

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    winapi::VK_PRIOR => return Ok(KeyPress::PageUp),
                    winapi::VK_NEXT => return Ok(KeyPress::PageDown),
                    // winapi::VK_BACK is correctly handled because the key_event.UnicodeChar is also set.
                    _ => continue,
                };
            } else if utf16 == 27 {
                return Ok(KeyPress::Esc);
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    return Ok(match c {
                        '-' => KeyPress::Meta('-'),
                        '0'...'9' => KeyPress::Meta(c),
                        '<' => KeyPress::Meta('<'),
                        '>' => KeyPress::Meta('>'),
                        'b' | 'B' => KeyPress::Meta('B'),
                        'c' | 'C' => KeyPress::Meta('C'),
                        'd' | 'D' => KeyPress::Meta('D'),
                        'f' | 'F' => KeyPress::Meta('F'),
                        'l' | 'L' => KeyPress::Meta('L'),
                        't' | 'T' => KeyPress::Meta('T'),
                        'u' | 'U' => KeyPress::Meta('U'),
                        'y' | 'Y' => KeyPress::Meta('Y'),
                        _ => {
                            debug!(target: "rustyline", "unsupported esc sequence: M-{:?}", c);
                            KeyPress::UnknownEscSeq
                        }
                    });
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl Iterator for ConsoleRawReader {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub type Terminal = Console;

#[derive(Clone,Debug)]
pub struct Console {
    stdin_isatty: bool,
    stdin_handle: winapi::HANDLE,
    stdout_handle: winapi::HANDLE,
}

impl Console {
    pub fn get_console_screen_buffer_info(&self) -> Result<winapi::CONSOLE_SCREEN_BUFFER_INFO> {
        let mut info = unsafe { mem::zeroed() };
        check!(kernel32::GetConsoleScreenBufferInfo(self.stdout_handle, &mut info));
        Ok(info)
    }

    pub fn set_console_cursor_position(&mut self, pos: winapi::COORD) -> Result<()> {
        check!(kernel32::SetConsoleCursorPosition(self.stdout_handle, pos));
        Ok(())
    }

    pub fn fill_console_output_character(&mut self,
                                         length: winapi::DWORD,
                                         pos: winapi::COORD)
                                         -> Result<()> {
        let mut _count = 0;
        check!(kernel32::FillConsoleOutputCharacterA(self.stdout_handle,
                                                     ' ' as winapi::CHAR,
                                                     length,
                                                     pos,
                                                     &mut _count));
        Ok(())
    }
}

impl Term for Console {
    type Reader = ConsoleRawReader;
    type Writer = Stdout;
    type Mode = Mode;

    fn new() -> Console {
        use std::ptr;
        let stdin_handle = get_std_handle(STDIN_FILENO);
        let stdin_isatty = match stdin_handle {
            Ok(handle) => {
                // If this function doesn't fail then fd is a TTY
                get_console_mode(handle).is_ok()
            }
            Err(_) => false,
        };

        let stdout_handle = get_std_handle(STDOUT_FILENO).unwrap_or(ptr::null_mut());
        Console {
            stdin_isatty: stdin_isatty,
            stdin_handle: stdin_handle.unwrap_or(ptr::null_mut()),
            stdout_handle: stdout_handle,
        }
    }

    /// Checking for an unsupported TERM in windows is a no-op
    fn is_unsupported(&self) -> bool {
        false
    }

    fn is_stdin_tty(&self) -> bool {
        self.stdin_isatty
    }

    // pub fn install_sigwinch_handler(&mut self) {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
    // }

    /// Try to get the number of columns in the current terminal,
    /// or assume 80 if it fails.
    fn get_columns(&self) -> usize {
        let (cols, _) = get_win_size(self.stdout_handle);
        cols
    }

    /// Try to get the number of rows in the current terminal,
    /// or assume 24 if it fails.
    fn get_rows(&self) -> usize {
        let (_, rows) = get_win_size(self.stdout_handle);
        rows
    }

    /// Enable RAW mode for the terminal.
    fn enable_raw_mode(&self) -> Result<Mode> {
        if !self.stdin_isatty {
            try!(Err(io::Error::new(io::ErrorKind::Other,
                                    "no stdio handle available for this process")));
        }
        let original_mode = try!(get_console_mode(self.stdin_handle));
        // Disable these modes
        let raw = original_mode &
                  !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                    winapi::wincon::ENABLE_PROCESSED_INPUT);
        // Enable these modes
        let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
        let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
        let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
        let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
        check!(kernel32::SetConsoleMode(self.stdin_handle, raw));
        Ok(Mode {
            original_mode: original_mode,
            stdin_handle: self.stdin_handle,
        })
    }

    fn create_reader(&self) -> Result<ConsoleRawReader> {
        ConsoleRawReader::new()
    }

    fn create_writer(&self) -> Stdout {
        io::stdout()
    }

    fn sigwinch(&self) -> bool {
        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, _: &mut Write) -> Result<()> {
        let info = try!(self.get_console_screen_buffer_info());
        let coord = winapi::COORD { X: 0, Y: 0 };
        check!(kernel32::SetConsoleCursorPosition(self.stdout_handle, coord));
        let mut _count = 0;
        let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
        check!(kernel32::FillConsoleOutputCharacterA(self.stdout_handle,
                                                     ' ' as winapi::CHAR,
                                                     n,
                                                     coord,
                                                     &mut _count));
        Ok(())
    }
}
<commit_msg>Fix Meta/Alt key handling on windows<commit_after>//! Windows specific definitions
use std::io::{self, Stdout, Write};
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use error;
use Result;
use super::{RawMode, RawReader, Term};

const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

fn get_win_size(handle: winapi::HANDLE) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, (1 + info.srWindow.Bottom - info.srWindow.Top) as usize),
    }
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<winapi::DWORD> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

pub type Mode = ConsoleMode;

#[derive(Clone,Copy,Debug)]
pub struct ConsoleMode {
    original_mode: winapi::DWORD,
    stdin_handle: winapi::HANDLE,
}

impl RawMode for Mode {
    /// Disable RAW mode for the terminal.
    fn disable_raw_mode(&self) -> Result<()> {
        check!(kernel32::SetConsoleMode(self.stdin_handle, self.original_mode));
        Ok(())
    }
}

/// Console input reader
pub struct ConsoleRawReader {
    handle: winapi::HANDLE,
    buf: Option<u16>,
}

impl ConsoleRawReader {
    pub fn new() -> Result<ConsoleRawReader> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(ConsoleRawReader {
            handle: handle,
            buf: None,
        })
    }
}

impl RawReader for ConsoleRawReader {
    fn next_key(&mut self, _: i32) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                debug!(target: "rustyline", "SIGWINCH");
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }
            // key_event.wRepeatCount seems to be always set to 1 (maybe because we only read one character at a time)

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) != 0;
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0;
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0;
            let meta = alt;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    winapi::VK_PRIOR => return Ok(KeyPress::PageUp),
                    winapi::VK_NEXT => return Ok(KeyPress::PageDown),
                    // winapi::VK_BACK is correctly handled because the key_event.UnicodeChar is also set.
                    _ => continue,
                };
            } else if utf16 == 27 {
                return Ok(KeyPress::Esc);
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    return Ok(match c {
                        '-' => KeyPress::Meta('-'),
                        '0'...'9' => KeyPress::Meta(c),
                        '<' => KeyPress::Meta('<'),
                        '>' => KeyPress::Meta('>'),
                        'b' | 'B' => KeyPress::Meta('B'),
                        'c' | 'C' => KeyPress::Meta('C'),
                        'd' | 'D' => KeyPress::Meta('D'),
                        'f' | 'F' => KeyPress::Meta('F'),
                        'l' | 'L' => KeyPress::Meta('L'),
                        't' | 'T' => KeyPress::Meta('T'),
                        'u' | 'U' => KeyPress::Meta('U'),
                        'y' | 'Y' => KeyPress::Meta('Y'),
                        _ => {
                            debug!(target: "rustyline", "unsupported esc sequence: M-{:?}", c);
                            KeyPress::UnknownEscSeq
                        }
                    });
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl Iterator for ConsoleRawReader {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub type Terminal = Console;

#[derive(Clone,Debug)]
pub struct Console {
    stdin_isatty: bool,
    stdin_handle: winapi::HANDLE,
    stdout_handle: winapi::HANDLE,
}

impl Console {
    pub fn get_console_screen_buffer_info(&self) -> Result<winapi::CONSOLE_SCREEN_BUFFER_INFO> {
        let mut info = unsafe { mem::zeroed() };
        check!(kernel32::GetConsoleScreenBufferInfo(self.stdout_handle, &mut info));
        Ok(info)
    }

    pub fn set_console_cursor_position(&mut self, pos: winapi::COORD) -> Result<()> {
        check!(kernel32::SetConsoleCursorPosition(self.stdout_handle, pos));
        Ok(())
    }

    pub fn fill_console_output_character(&mut self,
                                         length: winapi::DWORD,
                                         pos: winapi::COORD)
                                         -> Result<()> {
        let mut _count = 0;
        check!(kernel32::FillConsoleOutputCharacterA(self.stdout_handle,
                                                     ' ' as winapi::CHAR,
                                                     length,
                                                     pos,
                                                     &mut _count));
        Ok(())
    }
}

impl Term for Console {
    type Reader = ConsoleRawReader;
    type Writer = Stdout;
    type Mode = Mode;

    fn new() -> Console {
        use std::ptr;
        let stdin_handle = get_std_handle(STDIN_FILENO);
        let stdin_isatty = match stdin_handle {
            Ok(handle) => {
                // If this function doesn't fail then fd is a TTY
                get_console_mode(handle).is_ok()
            }
            Err(_) => false,
        };

        let stdout_handle = get_std_handle(STDOUT_FILENO).unwrap_or(ptr::null_mut());
        Console {
            stdin_isatty: stdin_isatty,
            stdin_handle: stdin_handle.unwrap_or(ptr::null_mut()),
            stdout_handle: stdout_handle,
        }
    }

    /// Checking for an unsupported TERM in windows is a no-op
    fn is_unsupported(&self) -> bool {
        false
    }

    fn is_stdin_tty(&self) -> bool {
        self.stdin_isatty
    }

    // pub fn install_sigwinch_handler(&mut self) {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
    // }

    /// Try to get the number of columns in the current terminal,
    /// or assume 80 if it fails.
    fn get_columns(&self) -> usize {
        let (cols, _) = get_win_size(self.stdout_handle);
        cols
    }

    /// Try to get the number of rows in the current terminal,
    /// or assume 24 if it fails.
    fn get_rows(&self) -> usize {
        let (_, rows) = get_win_size(self.stdout_handle);
        rows
    }

    /// Enable RAW mode for the terminal.
    fn enable_raw_mode(&self) -> Result<Mode> {
        if !self.stdin_isatty {
            try!(Err(io::Error::new(io::ErrorKind::Other,
                                    "no stdio handle available for this process")));
        }
        let original_mode = try!(get_console_mode(self.stdin_handle));
        // Disable these modes
        let raw = original_mode &
                  !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                    winapi::wincon::ENABLE_PROCESSED_INPUT);
        // Enable these modes
        let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
        let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
        let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
        let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
        check!(kernel32::SetConsoleMode(self.stdin_handle, raw));
        Ok(Mode {
            original_mode: original_mode,
            stdin_handle: self.stdin_handle,
        })
    }

    fn create_reader(&self) -> Result<ConsoleRawReader> {
        ConsoleRawReader::new()
    }

    fn create_writer(&self) -> Stdout {
        io::stdout()
    }

    fn sigwinch(&self) -> bool {
        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, _: &mut Write) -> Result<()> {
        let info = try!(self.get_console_screen_buffer_info());
        let coord = winapi::COORD { X: 0, Y: 0 };
        check!(kernel32::SetConsoleCursorPosition(self.stdout_handle, coord));
        let mut _count = 0;
        let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
        check!(kernel32::FillConsoleOutputCharacterA(self.stdout_handle,
                                                     ' ' as winapi::CHAR,
                                                     n,
                                                     coord,
                                                     &mut _count));
        Ok(())
    }
}
<|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 https://mozilla.org/MPL/2.0/.

//! Provides some utilities functions for escaping text (to HTML or
//! LaTeX) and formatting it according to typographic rules (smart
//! quotes, ellipsis, french rules for non-breaking spaces).
//!
//! These functions were originally written for
//! [Crowbook](https://github.com/lise-henry/crowbook), but have
//! been published on a separate crate and under a less restrictive
//! license (MPL instead of LGPL) so they can be used in other projects.
//!
//! # Usage
//!
//! Just add this line in the `dependencies` section of your `Cargo.toml`
//! file:
//!
//! ```toml
//! [dependencies]
//! crowbook-text-processing = "0.2"
//! ```
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::{FrenchFormatter, clean, escape};
//!
//! let s = " Some  string with  too much   whitespaces & around 1% \
//!          characters that might cause trouble to HTML or LaTeX.";
//! // Remove unnecessary whitespaces (but doesn't trim as it can have meaning)
//! let new_s = clean::whitespaces(s);
//! // Escape forHTML
//! println!("for HTML: {}", escape::html(new_s.clone()));
//! // Escape for LaTeX
//! println!("for LaTeX: {}", escape::tex(new_s));
//!
//! // Replace quotes with typographic quotation marks
//! let s = r#"Some "quoted string" and 'another one'."#;
//! let new_s = clean::quotes(s);
//! assert_eq!(&new_s, "Some “quoted string” and ‘another one’.");
//!
//! // Replace three consecutive dots with ellipsis character
//! let s = clean::ellipsis("Foo...");
//! assert_eq!(&s, "Foo…");
//!
//! // Format whitespaces according to french typographic rules, using
//! // the appropriate non-breaking spaces where needed
//! let s = " Une chaîne en français ! On voudrait un résultat \
//!          « typographiquement correct ».";
//! let french = FrenchFormatter::new();
//! println!("for text: {}", french.format(s));
//! println!("for LaTeX: {}", escape::tex(french.format_tex(s)));
//! ```
//! # Requirements
//!
//! * `rustc >= 1.6.0`
//!
//! # Semantic versioning
//!
//! While not yet at version `1.0`, this crates tries to follows semantic
//! versioning in the following way:
//!
//! * an increase of `x` in `0.x.y` means breaking changes.
//! * an increase of `y` in `0.x.y` means non-breaking changes.
extern crate regex;
#[macro_use]
extern crate lazy_static;

pub mod escape;
pub mod clean;

mod french;
mod common;

pub use french::FrenchFormatter;
<commit_msg>Add deny(missing_docs)<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 https://mozilla.org/MPL/2.0/.

//! Provides some utilities functions for escaping text (to HTML or
//! LaTeX) and formatting it according to typographic rules (smart
//! quotes, ellipsis, french rules for non-breaking spaces).
//!
//! These functions were originally written for
//! [Crowbook](https://github.com/lise-henry/crowbook), but have
//! been published on a separate crate and under a less restrictive
//! license (MPL instead of LGPL) so they can be used in other projects.
//!
//! # Usage
//!
//! Just add this line in the `dependencies` section of your `Cargo.toml`
//! file:
//!
//! ```toml
//! [dependencies]
//! crowbook-text-processing = "0.2"
//! ```
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::{FrenchFormatter, clean, escape};
//!
//! let s = " Some  string with  too much   whitespaces & around 1% \
//!          characters that might cause trouble to HTML or LaTeX.";
//! // Remove unnecessary whitespaces (but doesn't trim as it can have meaning)
//! let new_s = clean::whitespaces(s);
//! // Escape forHTML
//! println!("for HTML: {}", escape::html(new_s.clone()));
//! // Escape for LaTeX
//! println!("for LaTeX: {}", escape::tex(new_s));
//!
//! // Replace quotes with typographic quotation marks
//! let s = r#"Some "quoted string" and 'another one'."#;
//! let new_s = clean::quotes(s);
//! assert_eq!(&new_s, "Some “quoted string” and ‘another one’.");
//!
//! // Replace three consecutive dots with ellipsis character
//! let s = clean::ellipsis("Foo...");
//! assert_eq!(&s, "Foo…");
//!
//! // Format whitespaces according to french typographic rules, using
//! // the appropriate non-breaking spaces where needed
//! let s = " Une chaîne en français ! On voudrait un résultat \
//!          « typographiquement correct ».";
//! let french = FrenchFormatter::new();
//! println!("for text: {}", french.format(s));
//! println!("for LaTeX: {}", escape::tex(french.format_tex(s)));
//! ```
//! # Requirements
//!
//! * `rustc >= 1.6.0`
//!
//! # Semantic versioning
//!
//! While not yet at version `1.0`, this crates tries to follows semantic
//! versioning in the following way:
//!
//! * an increase of `x` in `0.x.y` means breaking changes.
//! * an increase of `y` in `0.x.y` means non-breaking changes.

#![deny(missing_docs)]

extern crate regex;
#[macro_use]
extern crate lazy_static;

pub mod escape;
pub mod clean;

mod french;
mod common;

pub use french::FrenchFormatter;
<|endoftext|>


<commit_before>//! NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
//! See "Kohonen neural networks for optimal colour quantization"
//! in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
//! for a discussion of the algorithm.
//! See also <https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/>

/* NeuQuant Neural-Net Quantization Algorithm
 * ------------------------------------------
 *
 * Copyright (c) 1994 Anthony Dekker
 *
 * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
 * See "Kohonen neural networks for optimal colour quantization"
 * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
 * for a discussion of the algorithm.
 * See also https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/
 *
 * Any party obtaining a copy of these files from the author, directly or
 * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
 * world-wide, paid up, royalty-free, nonexclusive right and license to deal
 * in this software and documentation files (the "Software"), including without
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons who receive
 * copies from any such party to do so, with the only requirement being
 * that this copyright notice remain intact.
 *
 *
 * Incorporated bugfixes and alpha channel handling from pngnq
 * http://pngnq.sourceforge.net
 *
 */

/// Neural network color quantizer
///
/// # Examples
/// ```
/// use image::imageops::colorops::{index_colors, ColorMap};
/// use image::math::nq::NeuQuant;
/// use image::{ImageBuffer, Rgba, RgbaImage};
///
/// // Create simple color image with RGBA pixels.
/// let (w, h) = (2, 2);
/// let red: Rgba<u8> = [255, 0, 0, 255].into();
/// let green: Rgba<u8> = [0, 255, 0, 255].into();
/// let blue: Rgba<u8> = [0, 0, 255, 255].into();
/// let white: Rgba<u8> = [255, 255, 255, 255].into();
/// let mut color_image = RgbaImage::new(w, h);
/// color_image.put_pixel(0, 0, red);
/// color_image.put_pixel(1, 0, green);
/// color_image.put_pixel(0, 1, blue);
/// color_image.put_pixel(1, 1, white);
///
/// // Create a `NeuQuant` colormap that will build an approximate color palette that best matches
/// // the original image.
/// // Note, the NeuQuant algorithm is only designed to work with 6-8 bit output, so `colors`
/// // should be a power of 2 in the range [64, 256].
/// let pixels = color_image.clone().into_raw();
/// let cmap = NeuQuant::new(1, 256, &pixels);
/// // Map the original image through the color map to create an indexed image stored in a
/// // `GrayImage`.
/// let palletized = index_colors(&color_image, &cmap);
/// // Map indexed image back `RgbaImage`.  Note the NeuQuant algorithm creates an approximation of
/// // the original colors, so even in this simple example the output is not pixel equivalent to
/// // the original.
/// let mapped = ImageBuffer::from_fn(w, h, |x, y| -> Rgba<u8> {
///     let p = palletized.get_pixel(x, y);
///     cmap.lookup(p.0[0] as usize)
///         .expect("indexed color out-of-range")
///         .into()
/// });
/// ```
#[deprecated(note = "Use the `color_quant` crate instead")]
pub type NeuQuant = color_quant::NeuQuant;
<commit_msg>Turn NeuQuant into newtype around color_quant type<commit_after>//! NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
//! See "Kohonen neural networks for optimal colour quantization"
//! in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
//! for a discussion of the algorithm.
//! See also <https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/>

/* NeuQuant Neural-Net Quantization Algorithm
 * ------------------------------------------
 *
 * Copyright (c) 1994 Anthony Dekker
 *
 * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
 * See "Kohonen neural networks for optimal colour quantization"
 * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
 * for a discussion of the algorithm.
 * See also https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/
 *
 * Any party obtaining a copy of these files from the author, directly or
 * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
 * world-wide, paid up, royalty-free, nonexclusive right and license to deal
 * in this software and documentation files (the "Software"), including without
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons who receive
 * copies from any such party to do so, with the only requirement being
 * that this copyright notice remain intact.
 *
 *
 * Incorporated bugfixes and alpha channel handling from pngnq
 * http://pngnq.sourceforge.net
 *
 */

/// Neural network color quantizer
///
/// # Examples
/// ```
/// use image::imageops::colorops::{index_colors, ColorMap};
/// use image::math::nq::NeuQuant;
/// use image::{ImageBuffer, Rgba, RgbaImage};
///
/// // Create simple color image with RGBA pixels.
/// let (w, h) = (2, 2);
/// let red: Rgba<u8> = [255, 0, 0, 255].into();
/// let green: Rgba<u8> = [0, 255, 0, 255].into();
/// let blue: Rgba<u8> = [0, 0, 255, 255].into();
/// let white: Rgba<u8> = [255, 255, 255, 255].into();
/// let mut color_image = RgbaImage::new(w, h);
/// color_image.put_pixel(0, 0, red);
/// color_image.put_pixel(1, 0, green);
/// color_image.put_pixel(0, 1, blue);
/// color_image.put_pixel(1, 1, white);
///
/// // Create a `NeuQuant` colormap that will build an approximate color palette that best matches
/// // the original image.
/// // Note, the NeuQuant algorithm is only designed to work with 6-8 bit output, so `colors`
/// // should be a power of 2 in the range [64, 256].
/// let pixels = color_image.clone().into_raw();
/// let cmap = NeuQuant::new(1, 256, &pixels);
/// // Map the original image through the color map to create an indexed image stored in a
/// // `GrayImage`.
/// let palletized = index_colors(&color_image, &cmap);
/// // Map indexed image back `RgbaImage`.  Note the NeuQuant algorithm creates an approximation of
/// // the original colors, so even in this simple example the output is not pixel equivalent to
/// // the original.
/// let mapped = ImageBuffer::from_fn(w, h, |x, y| -> Rgba<u8> {
///     let p = palletized.get_pixel(x, y);
///     cmap.lookup(p.0[0] as usize)
///         .expect("indexed color out-of-range")
///         .into()
/// });
/// ```
#[deprecated(note = "Use the `color_quant` crate instead")]
pub struct NeuQuant {
    inner: color_quant::NeuQuant,
}

/// The implementation only calls the corresponding inner `color_quant` methods.
///
/// These exist purely to keep a type separate from [`color_quant::NeuQuant`] and the interface
/// stable for this major version. The type will be changed to a pure re-export in the next
/// version or might be removed.
///
/// [`color_quant::NeuQuant`]: https://docs.rs/color_quant/1.1.0/color_quant/struct.NeuQuant.html
#[allow(deprecated)]
#[allow(missing_docs)]
impl NeuQuant {
    pub fn new(samplefac: i32, colors: usize, pixels: &[u8]) -> Self {
        NeuQuant { inner: color_quant::NeuQuant::new(samplefac, colors, pixels) }
    }
    pub fn init(&mut self, pixels: &[u8]) {
        self.inner.init(pixels)
    }
    pub fn map_pixel(&self, pixel: &mut [u8]) {
        self.inner.map_pixel(pixel)
    }
    pub fn index_of(&self, pixel: &[u8]) -> usize {
        self.inner.index_of(pixel)
    }
    pub fn lookup(&self, idx: usize) -> Option<[u8; 4]> {
        self.inner.lookup(idx)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use log::{error, warn};

use crate::args::Args;

pub fn send(message: rrg_proto::jobs::GrrMessage) {
        let data = protobuf::Message::write_to_bytes(&message)
            // Encoding can fail only if the buffer is insufficiently large. But
            // since we use growable vector this should never happen (provided
            // that we have enough memory).
            .expect("message encoding failure");

        let message = fleetspeak::Message {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data,
        };

        if let Err(error) = fleetspeak::send(message) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}

pub fn receive(args: &Args) -> Option<rrg_proto::jobs::GrrMessage> {
    use fleetspeak::ReadError::*;

    let message = match fleetspeak::receive_with_heartbeat(args.heartbeat_rate) {
        Ok(message) => message,
        Err(Malformed(error)) => {
            error!("received a malformed message: {}", error);
            return None;
        }
        Err(Decode(error)) => {
            error!("failed to decode a message: {}", error);
            return None;
        }
        Err(error) => {
            // If we failed to collect the message because of I/O error or magic
            // check, it means that our communication is broken (e.g. the pipe
            // was closed) and the agent should be killed.
            panic!("failed to collect a message: {}", error)
        }
    };

    if message.service != "GRR" {
        warn!("message send by '{}' service (instead of GRR)", message.service);
    }

    match message.kind {
        Some(ref kind) if kind != "GrrMessage" => {
            warn!("message with unrecognized type '{}'", kind);
        }
        Some(_) => (),
        None => {
            warn!("message with missing type specification");
        }
    }

    match protobuf::Message::parse_from_bytes(&message.data[..]) {
        Ok(message) => Some(message),
        Err(error) => {
            error!("failed to decode the data: {}", error);
            None
        }
    }
}
<commit_msg>Add TODO comments.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use log::{error, warn};

use crate::args::Args;

// TODO: Rename this to `send_raw` and unexpose it. Make it possible to only
// send the high-level types (`Item`, `Status`).
pub fn send(message: rrg_proto::jobs::GrrMessage) {
        let data = protobuf::Message::write_to_bytes(&message)
            // Encoding can fail only if the buffer is insufficiently large. But
            // since we use growable vector this should never happen (provided
            // that we have enough memory).
            .expect("message encoding failure");

        let message = fleetspeak::Message {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data,
        };

        if let Err(error) = fleetspeak::send(message) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}

// TODO: Rename this to `receive_raw` and unexpose it. Make it possible to only
// receive the high-level type (`Request`).
pub fn receive(args: &Args) -> Option<rrg_proto::jobs::GrrMessage> {
    use fleetspeak::ReadError::*;

    let message = match fleetspeak::receive_with_heartbeat(args.heartbeat_rate) {
        Ok(message) => message,
        Err(Malformed(error)) => {
            error!("received a malformed message: {}", error);
            return None;
        }
        Err(Decode(error)) => {
            error!("failed to decode a message: {}", error);
            return None;
        }
        Err(error) => {
            // If we failed to collect the message because of I/O error or magic
            // check, it means that our communication is broken (e.g. the pipe
            // was closed) and the agent should be killed.
            panic!("failed to collect a message: {}", error)
        }
    };

    if message.service != "GRR" {
        warn!("message send by '{}' service (instead of GRR)", message.service);
    }

    match message.kind {
        Some(ref kind) if kind != "GrrMessage" => {
            warn!("message with unrecognized type '{}'", kind);
        }
        Some(_) => (),
        None => {
            warn!("message with missing type specification");
        }
    }

    match protobuf::Message::parse_from_bytes(&message.data[..]) {
        Ok(message) => Some(message),
        Err(error) => {
            error!("failed to decode the data: {}", error);
            None
        }
    }
}
<|endoftext|>


<commit_before>use errors::Error;
use guards::{ReadGuard, WriteGuard};
use factory::FactoryBase;
use container::Container;
use reflect;

use downcast::Downcast;

use std::collections::BTreeMap;

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub trait Method<'a, Cont>
    where Cont: Container<'a>
{
    type Ret;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>>;
}

pub struct Read<Svc>(Svc);

impl<'a, Cont, Svc> Method<'a, Cont> for Read<Svc>
where
    Svc: reflect::Service<Key = Cont::Key>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Svc>,
{
    type Ret = ReadGuard<Svc, Cont::ServiceBase, Cont::ReadGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.read::<Svc>()
    }
}

pub struct Write<Svc>(fn(Svc));

impl<'a, Cont, Svc> Method<'a, Cont> for Write<Svc>
where
    Svc: reflect::Service<Key = Cont::Key>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Svc>,
{
    type Ret = WriteGuard<Svc, Cont::ServiceBase, Cont::WriteGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.write::<Svc>()
    }
}

pub struct ReadAll(());

impl<'a, Cont> Method<'a, Cont> for ReadAll
    where Cont: Container<'a>,
{
    type Ret = BTreeMap<&'a Cont::Key, Cont::ReadGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.read_all()
    }
}

pub struct WriteAll(());

impl<'a, Cont> Method<'a, Cont> for WriteAll
    where Cont: Container<'a>,
{
    type Ret = BTreeMap<&'a Cont::Key, Cont::WriteGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.write_all()
    }
}

pub struct Create<Obj>(fn(Obj));

impl<'a, Cont, Obj> Method<'a, Cont> for Create<Obj>
where
    Obj: reflect::FactoryObject<Key = Cont::Key>,
    Obj::Factory: FactoryBase<'a, Cont, Obj>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Obj::Factory>,
{
    type Ret = Obj;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.create::<Obj>()
    }
}

macro_rules! multi_methods {
    ($({$($params:ident: $fields:tt)+})+) => {$(

        #[allow(unused_assignments)] // FIXME `idx` get's falsely reported.
        impl<'a, Cont, $($params),+> Method<'a, Cont> for ($($params,)+)
            where Cont: Container<'a>, $($params: Method<'a, Cont> + 'a),+,
        {
            type Ret = ($($params::Ret,)+);

            fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok(($(
                    try!{$params::invoke(ioc)}
                ,)+))
            }
        }

    )+}
}

multi_methods!{
    {A:0}
    {A:0 B:1}
    {A:0 B:1 C:2}
    {A:0 B:1 C:2 D:3}
    {A:0 B:1 C:2 D:3 E:4}
    {A:0 B:1 C:2 D:3 E:4 F:5}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10 M:11}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10 M:11 N:12}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10 M:11 N:12 O:13}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10 M:11 N:12 O:13 P:14}
    {A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 J:8 K:9 L:10 M:11 N:12 O:13 P:14 Q:15}
}

<commit_msg>impl multi-{Read, Write, Create}<commit_after>use errors::Error;
use guards::{ReadGuard, WriteGuard};
use factory::FactoryBase;
use container::Container;
use reflect;

use downcast::Downcast;

use std::collections::BTreeMap;

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub trait Method<'a, Cont>
    where Cont: Container<'a>
{
    type Ret;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>>;
}

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub struct Read<Svc>(Svc);

impl<'a, Cont, Svc> Method<'a, Cont> for Read<Svc>
where
    Svc: reflect::Service<Key = Cont::Key>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Svc>,
{
    type Ret = ReadGuard<Svc, Cont::ServiceBase, Cont::ReadGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.read::<Svc>()
    }
}

macro_rules! multi_read {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Cont, $($params),+> Method<'a, Cont> for Read<($($params,)+)>
        where
            $($params: reflect::Service<Key = Cont::Key>),+,
            Cont: Container<'a>,
            $(Cont::ServiceBase: Downcast<$params>),+
        {
            type Ret = ($(<Read<$params> as Method<'a, Cont>>::Ret,)+);
            fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{ioc.read::<$params>()},)+
                ))
            }
        }
    )+}
}

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub struct Write<Svc>(fn(Svc));

impl<'a, Cont, Svc> Method<'a, Cont> for Write<Svc>
where
    Svc: reflect::Service<Key = Cont::Key>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Svc>,
{
    type Ret = WriteGuard<Svc, Cont::ServiceBase, Cont::WriteGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.write::<Svc>()
    }
}

macro_rules! multi_write {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Cont, $($params),+> Method<'a, Cont> for Write<($($params,)+)>
        where
            $($params: reflect::Service<Key = Cont::Key>),+,
            Cont: Container<'a>,
            $(Cont::ServiceBase: Downcast<$params>),+
        {
            type Ret = ($(<Write<$params> as Method<'a, Cont>>::Ret,)+);
            fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{ioc.write::<$params>()},)+
                ))
            }
        }
    )+}
}

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub struct Create<Obj>(fn(Obj));

impl<'a, Cont, Obj> Method<'a, Cont> for Create<Obj>
where
    Obj: reflect::FactoryObject<Key = Cont::Key>,
    Obj::Factory: FactoryBase<'a, Cont, Obj>,
    Cont: Container<'a>,
    Cont::ServiceBase: Downcast<Obj::Factory>,
{
    type Ret = Obj;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.create::<Obj>()
    }
}

macro_rules! multi_create {
    ($({$($params:ident)+})+) => {$(
        impl<'a, Cont, $($params),+> Method<'a, Cont> for Create<($($params,)+)>
        where
            $($params: reflect::FactoryObject<Key = Cont::Key>),+,
            $($params::Factory: FactoryBase<'a, Cont, $params>),+,
            Cont: Container<'a>,
            $(Cont::ServiceBase: Downcast<$params::Factory>),+
        {
            type Ret = ($(<Create<$params> as Method<'a, Cont>>::Ret,)+);
            fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{ioc.create::<$params>()},)+
                ))
            }
        }
    )+}
}

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub struct ReadAll(());

impl<'a, Cont> Method<'a, Cont> for ReadAll
    where Cont: Container<'a>,
{
    type Ret = BTreeMap<&'a Cont::Key, Cont::ReadGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.read_all()
    }
}

// ++++++++++++++++++++ Method ++++++++++++++++++++

pub struct WriteAll(());

impl<'a, Cont> Method<'a, Cont> for WriteAll
    where Cont: Container<'a>,
{
    type Ret = BTreeMap<&'a Cont::Key, Cont::WriteGuardBase>;
    fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
        ioc.write_all()
    }
}

// ++++++++++++++++++++ multi-method ++++++++++++++++++++

macro_rules! multi_methods {
    ($({$($params:ident)+})+) => {$(

        impl<'a, Cont, $($params),+> Method<'a, Cont> for ($($params,)+)
            where Cont: Container<'a>, $($params: Method<'a, Cont> + 'a),+,
        {
            type Ret = ($($params::Ret,)+);

            fn invoke(ioc: &'a Cont) -> Result<Self::Ret, Error<'a, Cont::Key>> {
                Ok((
                    $(try!{$params::invoke(ioc)},)+
                ))
            }
        }

    )+}
}

multi_read!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

multi_write!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

multi_create!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

multi_methods!{
    {A}
    {A B}
    {A B C}
    {A B C D}
    {A B C D E}
    {A B C D E F}
    {A B C D E F G}
    {A B C D E F G H}
    {A B C D E F G H J}
    {A B C D E F G H J K}
    {A B C D E F G H J K L}
    {A B C D E F G H J K L M}
    {A B C D E F G H J K L M N}
    {A B C D E F G H J K L M N O}
    {A B C D E F G H J K L M N O P}
    {A B C D E F G H J K L M N O P Q}
}

<|endoftext|>


<commit_before>use syntax::ast::*;
use rustc::lint::*;
use rustc::middle::ty;

use utils::{span_lint, match_type, walk_ptrs_ty};
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};

#[derive(Copy,Clone)]
pub struct MethodsPass;

declare_lint!(pub OPTION_UNWRAP_USED, Allow,
              "using `Option.unwrap()`, which should at least get a better message using `expect()`");
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
              "using `Result.unwrap()`, which might be better handled");
declare_lint!(pub STR_TO_STRING, Warn,
              "using `to_string()` on a str, which should be `to_owned()`");
declare_lint!(pub STRING_TO_STRING, Warn,
              "calling `String.to_string()` which is a no-op");

impl LintPass for MethodsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMethodCall(ref ident, _, ref args) = expr.node {
            let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0]));
            if ident.node.name == "unwrap" {
                if match_type(cx, obj_ty, &OPTION_PATH) {
                    span_lint(cx, OPTION_UNWRAP_USED, expr.span,
                              "used unwrap() on an Option value. If you don't want \
                               to handle the None case gracefully, consider using \
                               expect() to provide a better panic message");
                } else if match_type(cx, obj_ty, &RESULT_PATH) {
                    span_lint(cx, RESULT_UNWRAP_USED, expr.span,
                              "used unwrap() on a Result value. Graceful handling \
                               of Err values is preferred");
                }
            }
            else if ident.node.name == "to_string" {
                if obj_ty.sty == ty::TyStr {
                    span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster");
                } else if match_type(cx, obj_ty, &STRING_PATH) {
                    span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op");
                }
            }
        }
    }
}
<commit_msg>methods: people might be using to_string() to make a copy; add a hint for that<commit_after>use syntax::ast::*;
use rustc::lint::*;
use rustc::middle::ty;

use utils::{span_lint, match_type, walk_ptrs_ty};
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};

#[derive(Copy,Clone)]
pub struct MethodsPass;

declare_lint!(pub OPTION_UNWRAP_USED, Allow,
              "using `Option.unwrap()`, which should at least get a better message using `expect()`");
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
              "using `Result.unwrap()`, which might be better handled");
declare_lint!(pub STR_TO_STRING, Warn,
              "using `to_string()` on a str, which should be `to_owned()`");
declare_lint!(pub STRING_TO_STRING, Warn,
              "calling `String.to_string()` which is a no-op");

impl LintPass for MethodsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMethodCall(ref ident, _, ref args) = expr.node {
            let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0]));
            if ident.node.name == "unwrap" {
                if match_type(cx, obj_ty, &OPTION_PATH) {
                    span_lint(cx, OPTION_UNWRAP_USED, expr.span,
                              "used unwrap() on an Option value. If you don't want \
                               to handle the None case gracefully, consider using \
                               expect() to provide a better panic message");
                } else if match_type(cx, obj_ty, &RESULT_PATH) {
                    span_lint(cx, RESULT_UNWRAP_USED, expr.span,
                              "used unwrap() on a Result value. Graceful handling \
                               of Err values is preferred");
                }
            }
            else if ident.node.name == "to_string" {
                if obj_ty.sty == ty::TyStr {
                    span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster");
                } else if match_type(cx, obj_ty, &STRING_PATH) {
                    span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \
                                                                `clone()` to make a copy");
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>mod add;
mod build;
mod cmin;
mod fmt;
mod init;
mod list;
mod run;
mod tmin;

pub use self::{
    add::Add, build::Build, cmin::Cmin, fmt::Fmt, init::Init, list::List, run::Run, tmin::Tmin,
};

use std::fmt as stdfmt;
use std::str::FromStr;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy)]
pub enum Sanitizer {
    Address,
    Leak,
    Memory,
    Thread,
    None,
}

impl stdfmt::Display for Sanitizer {
    fn fmt(&self, f: &mut stdfmt::Formatter) -> stdfmt::Result {
        write!(
            f,
            "{}",
            match self {
                Sanitizer::Address => "address",
                Sanitizer::Leak => "leak",
                Sanitizer::Memory => "memory",
                Sanitizer::Thread => "thread",
                Sanitizer::None => "",
            }
        )
    }
}

impl FromStr for Sanitizer {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "address" => Ok(Sanitizer::Address),
            "leak" => Ok(Sanitizer::Leak),
            "memory" => Ok(Sanitizer::Memory),
            "thread" => Ok(Sanitizer::Thread),
            "none" => Ok(Sanitizer::None),
            _ => Err(format!("unknown sanitizer: {}", s)),
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct BuildOptions {
    #[structopt(short = "O", long = "release")]
    /// Build artifacts in release mode, with optimizations
    pub release: bool,

    /// Build target with verbose output from `cargo build`
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,

    #[structopt(short = "a", long = "debug-assertions")]
    /// Build artifacts with debug assertions enabled (default if not -O)
    pub debug_assertions: bool,

    #[structopt(long = "no-default-features")]
    /// Build artifacts with default Cargo features disabled
    pub no_default_features: bool,

    #[structopt(
        long = "all-features",
        conflicts_with = "no-default-features",
        conflicts_with = "features"
    )]
    /// Build artifacts with all Cargo features enabled
    pub all_features: bool,

    #[structopt(long = "features")]
    /// Build artifacts with given Cargo feature enabled
    pub features: Option<String>,

    #[structopt(
        short = "s",
        long = "sanitizer",
        possible_values(&["address", "leak", "memory", "thread", "none"]),
        default_value = "address",
    )]
    /// Use a specific sanitizer
    pub sanitizer: Sanitizer,

    #[structopt(
        name = "triple",
        long = "target",
        default_value(crate::utils::default_target())
    )]
    /// Target triple of the fuzz target
    pub triple: String,

    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    pub unstable_flags: Vec<String>,
}
<commit_msg>Add option for controlling overflow checks and an explicit option for debug mode<commit_after>mod add;
mod build;
mod cmin;
mod fmt;
mod init;
mod list;
mod run;
mod tmin;

pub use self::{
    add::Add, build::Build, cmin::Cmin, fmt::Fmt, init::Init, list::List, run::Run, tmin::Tmin,
};

use std::fmt as stdfmt;
use std::str::FromStr;
use structopt::StructOpt;

#[derive(Debug, Clone, Copy)]
pub enum Sanitizer {
    Address,
    Leak,
    Memory,
    Thread,
    None,
}

impl stdfmt::Display for Sanitizer {
    fn fmt(&self, f: &mut stdfmt::Formatter) -> stdfmt::Result {
        write!(
            f,
            "{}",
            match self {
                Sanitizer::Address => "address",
                Sanitizer::Leak => "leak",
                Sanitizer::Memory => "memory",
                Sanitizer::Thread => "thread",
                Sanitizer::None => "",
            }
        )
    }
}

impl FromStr for Sanitizer {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "address" => Ok(Sanitizer::Address),
            "leak" => Ok(Sanitizer::Leak),
            "memory" => Ok(Sanitizer::Memory),
            "thread" => Ok(Sanitizer::Thread),
            "none" => Ok(Sanitizer::None),
            _ => Err(format!("unknown sanitizer: {}", s)),
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct BuildOptions {
    #[structopt(short = "D", long = "debug", conflicts_with = "release")]
    /// Build artifacts in debug mode, without optimizations
    pub debug: bool,

    #[structopt(short = "O", long = "release", conflicts_with = "debug")]
    /// Build artifacts in release mode, with optimizations
    pub release: bool,

    #[structopt(short = "a", long = "debug-assertions")]
    /// Build artifacts with debug assertions enabled (default if not -O)
    pub debug_assertions: bool,

    #[structopt(short = "o", long = "overflow-checks")]
    /// Build artifacts with overflow checks enabled (default if not -O)
    pub overflow_checks: bool,

    /// Build target with verbose output from `cargo build`
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,

    #[structopt(long = "no-default-features")]
    /// Build artifacts with default Cargo features disabled
    pub no_default_features: bool,

    #[structopt(
        long = "all-features",
        conflicts_with = "no-default-features",
        conflicts_with = "features"
    )]
    /// Build artifacts with all Cargo features enabled
    pub all_features: bool,

    #[structopt(long = "features")]
    /// Build artifacts with given Cargo feature enabled
    pub features: Option<String>,

    #[structopt(
        short = "s",
        long = "sanitizer",
        possible_values(&["address", "leak", "memory", "thread", "none"]),
        default_value = "address",
    )]
    /// Use a specific sanitizer
    pub sanitizer: Sanitizer,

    #[structopt(
        name = "triple",
        long = "target",
        default_value(crate::utils::default_target())
    )]
    /// Target triple of the fuzz target
    pub triple: String,

    #[structopt(short = "Z", value_name = "FLAG")]
    /// Unstable (nightly-only) flags to Cargo
    pub unstable_flags: Vec<String>,
}
<|endoftext|>


<commit_before>pub use super::super::compiler::*;

use super::super::cache::Cache;
use super::postprocess;
use super::super::wincmd;
use super::super::utils::filter;
use super::super::utils::hash_text;
use super::super::io::tempfile::TempFile;

use std::fs::File;
use std::io::{Error, Cursor, Read, Write};
use std::hash::{SipHasher, Hasher};
use std::path::{Path, PathBuf};
use std::process::Output;

pub struct VsCompiler {
	cache: Cache,
	temp_dir: PathBuf
}

impl VsCompiler {
	pub fn new(cache: &Cache, temp_dir: &Path) -> Self {
		VsCompiler {
			cache: cache.clone(),
			temp_dir: temp_dir.to_path_buf()
		}
	}
}

impl Compiler for VsCompiler {
	fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<CompilationTask, String> {
		super::prepare::create_task(command, args)
	}

	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
		// Make parameters list for preprocessing.
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None,
			}
		});

		// Add preprocessor paramters.
		let temp_file = TempFile::new_in(&self.temp_dir, ".i");
		args.push("/nologo".to_string());
		args.push("/T".to_string() + &task.language);
		args.push("/P".to_string());
		args.push(task.input_source.display().to_string());

		// Hash data.
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		hash.write(&[0]);
		hash.write(wincmd::join(&args).as_bytes());

		let mut command = task.command.to_command();
		command
			.args(&args)
			.arg(&join_flag("/Fi", &temp_file.path()))
			.arg(&join_flag("/Fo", &task.output_object)); // /Fo option also set output path for #import directive
		let output = try! (command.output());
		if output.status.success() {
			match File::open(temp_file.path()) {
				Ok(mut stream) => {
					let mut output: Box<Read> = if task.input_precompiled.is_some() || task.output_precompiled.is_some() {
						let mut buffer: Vec<u8> = Vec::new();
						try! (postprocess::filter_preprocessed(&mut stream, &mut buffer, &task.marker_precompiled, task.output_precompiled.is_some()));
						Box::new(Cursor::new(buffer))
					} else {
						Box::new(stream)
					};
					let mut content = Vec::new();
					try! (output.read_to_end(&mut content));
					hash.write(&content);
					Ok(PreprocessResult::Success(PreprocessedSource {
						hash: format!("{:016x}", hash.finish()),
						content: content,
					}))
				}
				Err(e) => Err(e)
			}
		} else {
			Ok(PreprocessResult::Failed(OutputInfo::new(output)))
		}
	}

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessedSource) -> Result<OutputInfo, Error> {
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None
			}
		});
		args.push("/T".to_string() + &task.language);
		match &task.input_precompiled {
			&Some(ref path) => {
				args.push("/Yu".to_string());
				args.push("/Fp".to_string() + &path.display().to_string());
			}
			&None => {}
		}
		if task.output_precompiled.is_some() {
			args.push("/Yc".to_string());
		}
		// Input data, stored in files.
		let mut inputs: Vec<PathBuf> = Vec::new();
		match &task.input_precompiled {
				&Some(ref path) => {inputs.push(path.clone());}
				&None => {}
			}
		// Output files.
		let mut outputs: Vec<PathBuf> = Vec::new();
		outputs.push(task.output_object.clone());
		match &task.output_precompiled {
			&Some(ref path) => {
				outputs.push(path.clone());
			}
			&None => {}
		}

		let hash_params = hash_text(&preprocessed.content) + &wincmd::join(&args);
		self.cache.run_file_cached(&hash_params, &inputs, &outputs, || -> Result<OutputInfo, Error> {
			// Input file path.
			let input_temp = TempFile::new_in(&self.temp_dir, ".i");
			try! (try! (File::create(input_temp.path())).write_all(&preprocessed.content));
			// Run compiler.
			let mut command = task.command.to_command();
			command
				.args(&args)
				.arg(input_temp.path().to_str().unwrap())
				.arg("/c")
				.arg(&join_flag("/Fo", &task.output_object));
			match &task.input_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			match &task.output_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			command.output().map(|o| OutputInfo::new(o))
		}, || true)
	}
}

pub fn join_flag(flag: &str, path: &Path) -> String {
	flag.to_string() + &path.to_str().unwrap()
}<commit_msg>CL: Thread preprocessing warning C4002 as error<commit_after>pub use super::super::compiler::*;

use super::super::cache::Cache;
use super::postprocess;
use super::super::wincmd;
use super::super::utils::filter;
use super::super::utils::hash_text;
use super::super::io::tempfile::TempFile;

use std::fs::File;
use std::io::{Error, Cursor, Read, Write};
use std::hash::{SipHasher, Hasher};
use std::path::{Path, PathBuf};
use std::process::Output;

pub struct VsCompiler {
	cache: Cache,
	temp_dir: PathBuf
}

impl VsCompiler {
	pub fn new(cache: &Cache, temp_dir: &Path) -> Self {
		VsCompiler {
			cache: cache.clone(),
			temp_dir: temp_dir.to_path_buf()
		}
	}
}

impl Compiler for VsCompiler {
	fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<CompilationTask, String> {
		super::prepare::create_task(command, args)
	}

	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
		// Make parameters list for preprocessing.
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None,
			}
		});

		// Add preprocessor paramters.
		let temp_file = TempFile::new_in(&self.temp_dir, ".i");
		args.push("/nologo".to_string());
		args.push("/T".to_string() + &task.language);
		args.push("/P".to_string());
		args.push("/we4002".to_string()); // C4002: too many actual parameters for macro 'identifier'
		args.push(task.input_source.display().to_string());

		// Hash data.
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		hash.write(&[0]);
		hash.write(wincmd::join(&args).as_bytes());

		let mut command = task.command.to_command();
		command
			.args(&args)
			.arg(&join_flag("/Fi", &temp_file.path()))
			.arg(&join_flag("/Fo", &task.output_object)); // /Fo option also set output path for #import directive
		let output = try! (command.output());
		if output.status.success() {
			match File::open(temp_file.path()) {
				Ok(mut stream) => {
					let mut output: Box<Read> = if task.input_precompiled.is_some() || task.output_precompiled.is_some() {
						let mut buffer: Vec<u8> = Vec::new();
						try! (postprocess::filter_preprocessed(&mut stream, &mut buffer, &task.marker_precompiled, task.output_precompiled.is_some()));
						Box::new(Cursor::new(buffer))
					} else {
						Box::new(stream)
					};
					let mut content = Vec::new();
					try! (output.read_to_end(&mut content));
					hash.write(&content);
					Ok(PreprocessResult::Success(PreprocessedSource {
						hash: format!("{:016x}", hash.finish()),
						content: content,
					}))
				}
				Err(e) => Err(e)
			}
		} else {
			Ok(PreprocessResult::Failed(OutputInfo::new(output)))
		}
	}

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessedSource) -> Result<OutputInfo, Error> {
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None
			}
		});
		args.push("/T".to_string() + &task.language);
		match &task.input_precompiled {
			&Some(ref path) => {
				args.push("/Yu".to_string());
				args.push("/Fp".to_string() + &path.display().to_string());
			}
			&None => {}
		}
		if task.output_precompiled.is_some() {
			args.push("/Yc".to_string());
		}
		// Input data, stored in files.
		let mut inputs: Vec<PathBuf> = Vec::new();
		match &task.input_precompiled {
				&Some(ref path) => {inputs.push(path.clone());}
				&None => {}
			}
		// Output files.
		let mut outputs: Vec<PathBuf> = Vec::new();
		outputs.push(task.output_object.clone());
		match &task.output_precompiled {
			&Some(ref path) => {
				outputs.push(path.clone());
			}
			&None => {}
		}

		let hash_params = hash_text(&preprocessed.content) + &wincmd::join(&args);
		self.cache.run_file_cached(&hash_params, &inputs, &outputs, || -> Result<OutputInfo, Error> {
			// Input file path.
			let input_temp = TempFile::new_in(&self.temp_dir, ".i");
			try! (try! (File::create(input_temp.path())).write_all(&preprocessed.content));
			// Run compiler.
			let mut command = task.command.to_command();
			command
				.args(&args)
				.arg(input_temp.path().to_str().unwrap())
				.arg("/c")
				.arg(&join_flag("/Fo", &task.output_object));
			match &task.input_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			match &task.output_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			command.output().map(|o| OutputInfo::new(o))
		}, || true)
	}
}

pub fn join_flag(flag: &str, path: &Path) -> String {
	flag.to_string() + &path.to_str().unwrap()
}<|endoftext|>