<commit_before>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
#[cfg(unix)]
use crate::symbols::{bar, block, line, DOT};
#[cfg(unix)]
use pancurses::ToChtype;
#[cfg(unix)]
use unicode_segmentation::UnicodeSegmentation;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
            attribute: pancurses::Attribute::Normal,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(row as i32, col as i32);
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                if curses_style.attribute != pancurses::Attribute::Normal {
                    self.curses.win.attroff(curses_style.attribute);
                }
                let attribute: pancurses::Attribute = cell.style.modifier.into();
                self.curses.win.attron(attribute);
                curses_style.attribute = attribute;
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> Result<(), io::Error> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> Result<(), io::Error> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn clear(&mut self) -> Result<(), io::Error> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
    attribute: pancurses::Attribute,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = convert_to_curses_char(grapheme);
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    curses.print(symbol);
}

#[cfg(unix)]
/// Unicode to ASCII / ncurses extended characters
fn convert_to_curses_char(unicode: &str) -> pancurses::chtype {
    match unicode {
        line::TOP_RIGHT => pancurses::ACS_URCORNER(),
        line::VERTICAL => pancurses::ACS_VLINE(),
        line::HORIZONTAL => pancurses::ACS_HLINE(),
        line::TOP_LEFT => pancurses::ACS_ULCORNER(),
        line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
        line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
        line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
        line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
        line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
        line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
        block::FULL => pancurses::ACS_BLOCK(),
        block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
        block::THREE_QUATERS => pancurses::ACS_BLOCK(),
        block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
        block::HALF => pancurses::ACS_BLOCK(),
        block::THREE_EIGHTHS => pancurses::ACS_BLOCK(),
        block::ONE_QUATER => pancurses::ACS_BLOCK(),
        block::ONE_EIGHTH => pancurses::ACS_BLOCK(),
        bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
        bar::THREE_QUATERS => pancurses::ACS_BLOCK(),
        bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
        bar::HALF => pancurses::ACS_BLOCK(),
        bar::THREE_EIGHTHS => pancurses::ACS_BLOCK(),
        bar::ONE_QUATER => pancurses::ACS_BLOCK(),
        bar::ONE_EIGHTH => pancurses::ACS_BLOCK(),
        DOT => pancurses::ACS_BULLET(),
        unicode_char => {
            if unicode_char.is_ascii() {
                let mut chars = unicode_char.chars();
                if let Some(ch) = chars.next() {
                    ch.to_chtype()
                } else {
                    pancurses::ACS_BLOCK()
                }
            } else {
                pancurses::ACS_BLOCK()
            }
        }
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Rgb(_, _, _) => None,
        }
    }
}

impl From<Modifier> for pancurses::Attribute {
    fn from(modifier: Modifier) -> pancurses::Attribute {
        match modifier {
            Modifier::Blink => pancurses::Attribute::Blink,
            Modifier::Bold => pancurses::Attribute::Bold,
            Modifier::CrossedOut => pancurses::Attribute::Strikeout,
            Modifier::Faint => pancurses::Attribute::Dim,
            Modifier::Invert => pancurses::Attribute::Reverse,
            Modifier::Italic => pancurses::Attribute::Italic,
            Modifier::Underline => pancurses::Attribute::Underline,
            _ => pancurses::Attribute::Normal,
        }
    }
}
<commit_msg>fix: filter out wide unicode characters on windows<commit_after>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
use unicode_segmentation::UnicodeSegmentation;
use crate::symbols::{bar, block};
#[cfg(unix)]
use crate::symbols::{line, DOT};
#[cfg(unix)]
use pancurses::ToChtype;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
            attribute: pancurses::Attribute::Normal,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(row as i32, col as i32);
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                if curses_style.attribute != pancurses::Attribute::Normal {
                    self.curses.win.attroff(curses_style.attribute);
                }
                let attribute: pancurses::Attribute = cell.style.modifier.into();
                self.curses.win.attron(attribute);
                curses_style.attribute = attribute;
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> Result<(), io::Error> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> Result<(), io::Error> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn clear(&mut self) -> Result<(), io::Error> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
    attribute: pancurses::Attribute,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            line::TOP_RIGHT => pancurses::ACS_URCORNER(),
            line::VERTICAL => pancurses::ACS_VLINE(),
            line::HORIZONTAL => pancurses::ACS_HLINE(),
            line::TOP_LEFT => pancurses::ACS_ULCORNER(),
            line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
            line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
            line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
            line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
            line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
            line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
            block::FULL => pancurses::ACS_BLOCK(),
            block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            block::THREE_QUATERS => pancurses::ACS_BLOCK(),
            block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            block::HALF => pancurses::ACS_BLOCK(),
            block::THREE_EIGHTHS => ' ' as u64,
            block::ONE_QUATER => ' ' as u64,
            block::ONE_EIGHTH => ' ' as u64,
            bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::THREE_QUATERS => pancurses::ACS_BLOCK(),
            bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::HALF => pancurses::ACS_BLOCK(),
            bar::THREE_EIGHTHS => pancurses::ACS_S9(),
            bar::ONE_QUATER => pancurses::ACS_S9(),
            bar::ONE_EIGHTH => pancurses::ACS_S9(),
            DOT => pancurses::ACS_BULLET(),
            unicode_char => {
                if unicode_char.is_ascii() {
                    let mut chars = unicode_char.chars();
                    if let Some(ch) = chars.next() {
                        ch.to_chtype()
                    } else {
                        pancurses::ACS_BLOCK()
                    }
                } else {
                    pancurses::ACS_BLOCK()
                }
            }
        };
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            block::SEVEN_EIGHTHS => block::FULL,
            block::THREE_QUATERS => block::FULL,
            block::FIVE_EIGHTHS => block::HALF,
            block::THREE_EIGHTHS => block::HALF,
            block::ONE_QUATER => block::HALF,
            block::ONE_EIGHTH => " ",
            bar::SEVEN_EIGHTHS => bar::FULL,
            bar::THREE_QUATERS => bar::FULL,
            bar::FIVE_EIGHTHS => bar::HALF,
            bar::THREE_EIGHTHS => bar::HALF,
            bar::ONE_QUATER => bar::HALF,
            bar::ONE_EIGHTH => " ",
            ch => ch,
        };
        // curses.win.addch(ch);
        curses.print(ch);
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Rgb(_, _, _) => None,
        }
    }
}

impl From<Modifier> for pancurses::Attribute {
    fn from(modifier: Modifier) -> pancurses::Attribute {
        match modifier {
            Modifier::Blink => pancurses::Attribute::Blink,
            Modifier::Bold => pancurses::Attribute::Bold,
            Modifier::CrossedOut => pancurses::Attribute::Strikeout,
            Modifier::Faint => pancurses::Attribute::Dim,
            Modifier::Invert => pancurses::Attribute::Reverse,
            Modifier::Italic => pancurses::Attribute::Italic,
            Modifier::Underline => pancurses::Attribute::Underline,
            _ => pancurses::Attribute::Normal,
        }
    }
}
<|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 api::{TileOffset, LayerRect, LayerSize, LayerVector2D, DeviceUintSize};
use euclid::rect;

pub struct DecomposedTile {
    pub rect: LayerRect,
    pub stretch_size: LayerSize,
    pub tile_offset: TileOffset,
}

pub struct TiledImageInfo {
    /// The bounds of the item in layout space.
    pub rect: LayerRect,
    /// The space between each repeated pattern in layout space.
    pub tile_spacing: LayerSize,
    /// The size in layout space of each repetition of the image.
    pub stretch_size: LayerSize,

    /// The size the image occupies in the cache in device space.
    pub device_image_size: DeviceUintSize,
    /// The size of the tiles in the cache in device pixels.
    pub device_tile_size: u32,
}

/// Decomposes an image that is repeated into an image per individual repetition.
/// We need to do this when we are unable to perform the repetition in the shader,
/// for example if the image is tiled.
///
/// In all of the "decompose" methods below, we independently handle horizontal and vertical
/// decomposition. This lets us generate the minimum amount of primitives by, for  example,
/// decompositing the repetition horizontally while repeating vertically in the shader (for
/// an image where the width is too bug but the height is not).
///
/// decompose_image and decompose_row handle image repetitions while decompose_cache_tiles
/// takes care of the decomposition required by the internal tiling of the image in the cache.
///
/// Note that the term tiling is overloaded: There is the tiling we get from repeating images
/// in layout space, and the tiling that we do in the texture cache (to avoid hitting texture
/// size limits). The latter is referred to as "device" tiling here to disambiguate.
pub fn decompose_image(info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {

    let no_vertical_tiling = info.device_image_size.height <= info.device_tile_size;
    let no_vertical_spacing = info.tile_spacing.height == 0.0;

    if no_vertical_tiling && no_vertical_spacing {
        decompose_row(&info.rect, info, callback);
        return;
    }

    // Decompose each vertical repetition into rows.
    let layout_stride = info.stretch_size.height + info.tile_spacing.height;
    let num_repetitions = (info.rect.size.height / layout_stride).ceil() as u32;

    for i in 0 .. num_repetitions {
        let row_rect = rect(
            info.rect.origin.x,
            info.rect.origin.y + (i as f32) * layout_stride,
            info.rect.size.width,
            info.stretch_size.height,
        ).intersection(&info.rect);

        if let Some(row_rect) = row_rect {
            decompose_row(&row_rect, info, callback);
        }
    }
}

fn decompose_row(item_rect: &LayerRect, info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {

    let no_horizontal_tiling = info.device_image_size.width <= info.device_tile_size;
    let no_horizontal_spacing = info.tile_spacing.width == 0.0;

    if no_horizontal_tiling && no_horizontal_spacing {
        decompose_cache_tiles(item_rect, info, callback);
        return;
    }

    // Decompose each horizontal repetition.
    let layout_stride = info.stretch_size.width + info.tile_spacing.width;
    let num_repetitions = (item_rect.size.width / layout_stride).ceil() as u32;

    for i in 0 .. num_repetitions {
        let decomposed_rect = rect(
            item_rect.origin.x + (i as f32) * layout_stride,
            item_rect.origin.y,
            info.stretch_size.width,
            item_rect.size.height,
        ).intersection(&item_rect);

        if let Some(decomposed_rect) = decomposed_rect {
            decompose_cache_tiles(&decomposed_rect, info, callback);
        }
    }
}

fn decompose_cache_tiles(
    item_rect: &LayerRect,
    info: &TiledImageInfo,
    callback: &mut FnMut(&DecomposedTile),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is plit into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated image primitive corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.
    //
    // For the case where we don't tile along an axis, we can still perform the repetition in
    // the shader (for this particular axis), and it is worth special-casing for this to avoid
    // generating many primitives.
    // This can happen with very tall and thin images used as a repeating background.
    // Apparently web authors do that...

    let needs_repeat_x = info.stretch_size.width < item_rect.size.width;
    let needs_repeat_y = info.stretch_size.height < item_rect.size.height;

    let tiled_in_x = info.device_image_size.width > info.device_tile_size;
    let tiled_in_y = info.device_image_size.height > info.device_tile_size;

    // If we don't actually tile in this dimension, repeating can be done in the shader.
    let shader_repeat_x = needs_repeat_x && !tiled_in_x;
    let shader_repeat_y = needs_repeat_y && !tiled_in_y;

    let tile_size_f32 = info.device_tile_size as f32;

    // Note: this rounds down so it excludes the partially filled tiles on the right and
    // bottom edges (we handle them separately below).
    let num_tiles_x = (info.device_image_size.width / info.device_tile_size) as u16;
    let num_tiles_y = (info.device_image_size.height / info.device_tile_size) as u16;

    // Ratio between (image space) tile size and image size.
    let img_dw = tile_size_f32 / (info.device_image_size.width as f32);
    let img_dh = tile_size_f32 / (info.device_image_size.height as f32);

    // Strected size of the tile in layout space.
    let stretched_tile_size = LayerSize::new(
        img_dw * info.stretch_size.width,
        img_dh * info.stretch_size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover = DeviceUintSize::new(
        info.device_image_size.width % info.device_tile_size,
        info.device_image_size.height % info.device_tile_size
    );

    for ty in 0 .. num_tiles_y {
        for tx in 0 .. num_tiles_x {
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(tx, ty),
                1.0,
                1.0,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
        if leftover.width != 0 {
            // Tiles on the right edge that are smaller than the tile size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(num_tiles_x, ty),
                (leftover.width as f32) / tile_size_f32,
                1.0,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
    }

    if leftover.height != 0 {
        for tx in 0 .. num_tiles_x {
            // Tiles on the bottom edge that are smaller than the tile size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(tx, num_tiles_y),
                1.0,
                (leftover.height as f32) / tile_size_f32,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }

        if leftover.width != 0 {
            // Finally, the bottom-right tile with a "leftover" size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(num_tiles_x, num_tiles_y),
                (leftover.width as f32) / tile_size_f32,
                (leftover.height as f32) / tile_size_f32,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
    }
}

fn add_device_tile(
    item_rect: &LayerRect,
    stretched_tile_size: LayerSize,
    tile_offset: TileOffset,
    tile_ratio_width: f32,
    tile_ratio_height: f32,
    shader_repeat_x: bool,
    shader_repeat_y: bool,
    callback: &mut FnMut(&DecomposedTile),
) {
    // If the the image is tiled along a given axis, we can't have the shader compute
    // the image repetition pattern. In this case we base the primitive's rectangle size
    // on the stretched tile size which effectively cancels the repetion (and repetition
    // has to be emulated by generating more primitives).
    // If the image is not tiled along this axis, we can perform the repetition in the
    // shader. in this case we use the item's size in the primitive (on that particular
    // axis).
    // See the shader_repeat_x/y code below.

    let stretch_size = LayerSize::new(
        stretched_tile_size.width * tile_ratio_width,
        stretched_tile_size.height * tile_ratio_height,
    );

    let mut prim_rect = LayerRect::new(
        item_rect.origin + LayerVector2D::new(
            tile_offset.x as f32 * stretched_tile_size.width,
            tile_offset.y as f32 * stretched_tile_size.height,
        ),
        stretch_size,
    );

    if shader_repeat_x {
        assert_eq!(tile_offset.x, 0);
        prim_rect.size.width = item_rect.size.width;
    }

    if shader_repeat_y {
        assert_eq!(tile_offset.y, 0);
        prim_rect.size.height = item_rect.size.height;
    }

    // Fix up the primitive's rect if it overflows the original item rect.
    if let Some(rect) = prim_rect.intersection(&item_rect) {
        callback(&DecomposedTile {
            tile_offset,
            rect,
            stretch_size,
        });
    }
}
<commit_msg>Fixed some spelling mistakes in image.rs<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 api::{TileOffset, LayerRect, LayerSize, LayerVector2D, DeviceUintSize};
use euclid::rect;

pub struct DecomposedTile {
    pub rect: LayerRect,
    pub stretch_size: LayerSize,
    pub tile_offset: TileOffset,
}

pub struct TiledImageInfo {
    /// The bounds of the item in layout space.
    pub rect: LayerRect,
    /// The space between each repeated pattern in layout space.
    pub tile_spacing: LayerSize,
    /// The size in layout space of each repetition of the image.
    pub stretch_size: LayerSize,

    /// The size the image occupies in the cache in device space.
    pub device_image_size: DeviceUintSize,
    /// The size of the tiles in the cache in device pixels.
    pub device_tile_size: u32,
}

/// Decomposes an image that is repeated into an image per individual repetition.
/// We need to do this when we are unable to perform the repetition in the shader,
/// for example if the image is tiled.
///
/// In all of the "decompose" methods below, we independently handle horizontal and vertical
/// decomposition. This lets us generate the minimum amount of primitives by, for example,
/// decomposing the repetition horizontally while repeating vertically in the shader (for
/// an image where the width is too bug but the height is not).
///
/// decompose_image and decompose_row handle image repetitions while decompose_cache_tiles
/// takes care of the decomposition required by the internal tiling of the image in the cache.
///
/// Note that the term tiling is overloaded: There is the tiling we get from repeating images
/// in layout space, and the tiling that we do in the texture cache (to avoid hitting texture
/// size limits). The latter is referred to as "device" tiling here to disambiguate.
pub fn decompose_image(info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {

    let no_vertical_tiling = info.device_image_size.height <= info.device_tile_size;
    let no_vertical_spacing = info.tile_spacing.height == 0.0;

    if no_vertical_tiling && no_vertical_spacing {
        decompose_row(&info.rect, info, callback);
        return;
    }

    // Decompose each vertical repetition into rows.
    let layout_stride = info.stretch_size.height + info.tile_spacing.height;
    let num_repetitions = (info.rect.size.height / layout_stride).ceil() as u32;

    for i in 0 .. num_repetitions {
        let row_rect = rect(
            info.rect.origin.x,
            info.rect.origin.y + (i as f32) * layout_stride,
            info.rect.size.width,
            info.stretch_size.height,
        ).intersection(&info.rect);

        if let Some(row_rect) = row_rect {
            decompose_row(&row_rect, info, callback);
        }
    }
}

fn decompose_row(item_rect: &LayerRect, info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {

    let no_horizontal_tiling = info.device_image_size.width <= info.device_tile_size;
    let no_horizontal_spacing = info.tile_spacing.width == 0.0;

    if no_horizontal_tiling && no_horizontal_spacing {
        decompose_cache_tiles(item_rect, info, callback);
        return;
    }

    // Decompose each horizontal repetition.
    let layout_stride = info.stretch_size.width + info.tile_spacing.width;
    let num_repetitions = (item_rect.size.width / layout_stride).ceil() as u32;

    for i in 0 .. num_repetitions {
        let decomposed_rect = rect(
            item_rect.origin.x + (i as f32) * layout_stride,
            item_rect.origin.y,
            info.stretch_size.width,
            item_rect.size.height,
        ).intersection(&item_rect);

        if let Some(decomposed_rect) = decomposed_rect {
            decompose_cache_tiles(&decomposed_rect, info, callback);
        }
    }
}

fn decompose_cache_tiles(
    item_rect: &LayerRect,
    info: &TiledImageInfo,
    callback: &mut FnMut(&DecomposedTile),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is split into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated image primitive corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.
    //
    // For the case where we don't tile along an axis, we can still perform the repetition in
    // the shader (for this particular axis), and it is worth special-casing for this to avoid
    // generating many primitives.
    // This can happen with very tall and thin images used as a repeating background.
    // Apparently web authors do that...

    let needs_repeat_x = info.stretch_size.width < item_rect.size.width;
    let needs_repeat_y = info.stretch_size.height < item_rect.size.height;

    let tiled_in_x = info.device_image_size.width > info.device_tile_size;
    let tiled_in_y = info.device_image_size.height > info.device_tile_size;

    // If we don't actually tile in this dimension, repeating can be done in the shader.
    let shader_repeat_x = needs_repeat_x && !tiled_in_x;
    let shader_repeat_y = needs_repeat_y && !tiled_in_y;

    let tile_size_f32 = info.device_tile_size as f32;

    // Note: this rounds down so it excludes the partially filled tiles on the right and
    // bottom edges (we handle them separately below).
    let num_tiles_x = (info.device_image_size.width / info.device_tile_size) as u16;
    let num_tiles_y = (info.device_image_size.height / info.device_tile_size) as u16;

    // Ratio between (image space) tile size and image size.
    let img_dw = tile_size_f32 / (info.device_image_size.width as f32);
    let img_dh = tile_size_f32 / (info.device_image_size.height as f32);

    // Stretched size of the tile in layout space.
    let stretched_tile_size = LayerSize::new(
        img_dw * info.stretch_size.width,
        img_dh * info.stretch_size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover = DeviceUintSize::new(
        info.device_image_size.width % info.device_tile_size,
        info.device_image_size.height % info.device_tile_size
    );

    for ty in 0 .. num_tiles_y {
        for tx in 0 .. num_tiles_x {
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(tx, ty),
                1.0,
                1.0,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
        if leftover.width != 0 {
            // Tiles on the right edge that are smaller than the tile size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(num_tiles_x, ty),
                (leftover.width as f32) / tile_size_f32,
                1.0,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
    }

    if leftover.height != 0 {
        for tx in 0 .. num_tiles_x {
            // Tiles on the bottom edge that are smaller than the tile size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(tx, num_tiles_y),
                1.0,
                (leftover.height as f32) / tile_size_f32,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }

        if leftover.width != 0 {
            // Finally, the bottom-right tile with a "leftover" size.
            add_device_tile(
                item_rect,
                stretched_tile_size,
                TileOffset::new(num_tiles_x, num_tiles_y),
                (leftover.width as f32) / tile_size_f32,
                (leftover.height as f32) / tile_size_f32,
                shader_repeat_x,
                shader_repeat_y,
                callback,
            );
        }
    }
}

fn add_device_tile(
    item_rect: &LayerRect,
    stretched_tile_size: LayerSize,
    tile_offset: TileOffset,
    tile_ratio_width: f32,
    tile_ratio_height: f32,
    shader_repeat_x: bool,
    shader_repeat_y: bool,
    callback: &mut FnMut(&DecomposedTile),
) {
    // If the image is tiled along a given axis, we can't have the shader compute
    // the image repetition pattern. In this case we base the primitive's rectangle size
    // on the stretched tile size which effectively cancels the repetition (and repetition
    // has to be emulated by generating more primitives).
    // If the image is not tiled along this axis, we can perform the repetition in the
    // shader. In this case we use the item's size in the primitive (on that particular
    // axis).
    // See the shader_repeat_x/y code below.

    let stretch_size = LayerSize::new(
        stretched_tile_size.width * tile_ratio_width,
        stretched_tile_size.height * tile_ratio_height,
    );

    let mut prim_rect = LayerRect::new(
        item_rect.origin + LayerVector2D::new(
            tile_offset.x as f32 * stretched_tile_size.width,
            tile_offset.y as f32 * stretched_tile_size.height,
        ),
        stretch_size,
    );

    if shader_repeat_x {
        assert_eq!(tile_offset.x, 0);
        prim_rect.size.width = item_rect.size.width;
    }

    if shader_repeat_y {
        assert_eq!(tile_offset.y, 0);
        prim_rect.size.height = item_rect.size.height;
    }

    // Fix up the primitive's rect if it overflows the original item rect.
    if let Some(rect) = prim_rect.intersection(&item_rect) {
        callback(&DecomposedTile {
            tile_offset,
            rect,
            stretch_size,
        });
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::PathBuf;
use std::str::FromStr;

use toml;

pub use bindgen::annotation::*;
pub use bindgen::rename::*;

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// A language type to generate bindings for.
#[derive(Debug, Clone, PartialEq)]
pub enum Language {
    Cxx,
    C,
}

// A style of braces to use for generating code.
#[derive(Debug, Clone, PartialEq)]
pub enum Braces {
    SameLine,
    NextLine,
}

// A type of layout to use when generating long lines of code.
#[derive(Debug, Clone, PartialEq)]
pub enum Layout {
    Horizontal,
    Vertical,
    Auto,
}

impl FromStr for Language {
    type Err = String;

    fn from_str(s: &str) -> Result<Language, Self::Err> {
        match s {
            "cxx" => Ok(Language::Cxx),
            "Cxx" => Ok(Language::Cxx),
            "CXX" => Ok(Language::Cxx),
            "cpp" => Ok(Language::Cxx),
            "Cpp" => Ok(Language::Cxx),
            "CPP" => Ok(Language::Cxx),
            "c++" => Ok(Language::Cxx),
            "C++" => Ok(Language::Cxx),
            "c" => Ok(Language::C),
            "C" => Ok(Language::C),
            _ => Err(format!("unrecognized Language: '{}'", s)),
        }
    }
}
impl FromStr for Braces {
    type Err = String;

    fn from_str(s: &str) -> Result<Braces, Self::Err> {
        match s {
            "SameLine" => Ok(Braces::SameLine),
            "same_line" => Ok(Braces::SameLine),
            "NextLine" => Ok(Braces::NextLine),
            "next_line" => Ok(Braces::NextLine),
            _ => Err(format!("unrecognized Braces: '{}'", s)),
        }
    }
}
impl FromStr for Layout {
    type Err = String;

    fn from_str(s: &str) -> Result<Layout, Self::Err> {
        match s {
            "Horizontal" => Ok(Layout::Horizontal),
            "horizontal" => Ok(Layout::Horizontal),
            "Vertical" => Ok(Layout::Vertical),
            "vertical" => Ok(Layout::Vertical),
            "Auto" => Ok(Layout::Auto),
            "auto" => Ok(Layout::Auto),
            _ => Err(format!("unrecognized Layout: '{}'", s)),
        }
    }
}

deserialize_enum_str!(Language);
deserialize_enum_str!(Braces);
deserialize_enum_str!(Layout);

/// A collection of settings to customize the generated bindings.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct Config {
    /// Optional text to output at the beginning of the file
    pub header: Option<String>,
    /// Optional text to output at the end of the file
    pub trailer: Option<String>,
    /// Option name to use for an include guard
    pub include_guard: Option<String>,
    /// Optional text to output at major sections to deter manual editing
    pub autogen_warning: Option<String>,
    /// Include a comment with the version of cbindgen used to generate the file
    pub include_version: bool,
    /// The style to use for braces
    pub braces: Braces,
    /// The preferred length of a line, used for auto breaking function arguments
    pub line_length: usize,
    /// The amount of spaces in a tab
    pub tab_width: usize,
    /// The language to output bindings for
    pub language: Language,
    /// The configuration options for functions
    #[serde(rename = "fn")]
    pub function: FunctionConfig,
    /// The configuration options for structs
    #[serde(rename = "struct")]
    pub structure: StructConfig,
    /// The configuration options for enums
    #[serde(rename = "enum")]
    pub enumeration: EnumConfig,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            header: None,
            trailer: None,
            include_guard: None,
            autogen_warning: None,
            include_version: true,
            braces: Braces::SameLine,
            line_length: 100,
            tab_width: 2,
            language: Language::Cxx,
            function: FunctionConfig::default(),
            structure: StructConfig::default(),
            enumeration: EnumConfig::default(),
        }
    }
}

/// Settings to apply to generated functions.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct FunctionConfig {
    /// Optional text to output before each function declaration
    pub prefix: Option<String>,
    /// Optional text to output after each function declaration
    pub postfix: Option<String>,
    /// The style to layout the args
    pub args: Layout,
    /// The rename rule to apply to function args
    pub rename_args: Option<RenameRule>,
}

impl Default for FunctionConfig {
    fn default() -> FunctionConfig {
        FunctionConfig {
            prefix: None,
            postfix: None,
            args: Layout::Auto,
            rename_args: None,
        }
    }
}

/// Settings to apply to generated structs.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct StructConfig {
    /// The rename rule to apply to the name of struct fields
    pub rename_fields: Option<RenameRule>,
    /// Whether to generate a piecewise equality operator
    pub derive_eq: bool,
    /// Whether to generate a piecewise inequality operator
    pub derive_neq: bool,
    /// Whether to generate a less than operator on structs with one field
    pub derive_lt: bool,
    /// Whether to generate a less than or equal to operator on structs with one field
    pub derive_lte: bool,
    /// Whether to generate a greater than operator on structs with one field
    pub derive_gt: bool,
    /// Whether to generate a greater than or equal to operator on structs with one field
    pub derive_gte: bool,
}

impl Default for StructConfig {
    fn default() -> StructConfig {
        StructConfig {
            rename_fields: None,
            derive_eq: false,
            derive_neq: false,
            derive_lt: false,
            derive_lte: false,
            derive_gt: false,
            derive_gte: false,
        }
    }
}

/// Settings to apply to generated enums.
#[derive( Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct EnumConfig {
    /// The rename rule to apply to the name of enum variants
    pub rename_variants: Option<RenameRule>,
    /// Whether to add a `Sentinel` value at the end of every enum
    /// This is useful in Gecko for IPC serialization
    pub add_sentinel: bool,
}

impl Default for EnumConfig {
    fn default() -> EnumConfig {
        EnumConfig {
            rename_variants: None,
            add_sentinel: false,
        }
    }
}

impl Config {
    pub fn from_file(file_name: &str) -> Result<Config, String> {
        fn read(file_name: &str) -> io::Result<String> {
            let file = File::open(file_name)?;
            let mut reader = BufReader::new(&file);
            let mut contents = String::new();
            reader.read_to_string(&mut contents)?;
            Ok(contents)
        }

        let config_text = read(file_name).unwrap();

        match toml::from_str::<Config>(&config_text) {
            Ok(x) => Ok(x),
            Err(e) => Err(format!("couldn't parse config file: {}", e)),
        }
    }

    pub fn from_root_or_default(root: &str) -> Config {
        let c = PathBuf::from(root).join("cbindgen.toml");

        if c.exists() {
            Config::from_file(c.to_str().unwrap()).unwrap()
        } else {
            Config::default()
        }
    }
}

impl FunctionConfig {
    pub fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
        if let Some(x) = annotations.atom("prefix") {
            return x;
        }
        self.prefix.clone()
    }

    pub fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
        if let Some(x) = annotations.atom("postfix") {
            return x;
        }
        self.postfix.clone()
    }
}

impl StructConfig {
    pub fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-eq") {
            return x;
        }
        self.derive_eq
    }
    pub fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-neq") {
            return x;
        }
        self.derive_neq
    }
    pub fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-lt") {
            return x;
        }
        self.derive_lt
    }
    pub fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-lte") {
            return x;
        }
        self.derive_lte
    }
    pub fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-gt") {
            return x;
        }
        self.derive_gt
    }
    pub fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-gte") {
            return x;
        }
        self.derive_gte
    }
}

impl EnumConfig {
    pub fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("add-sentinel") {
            return x;
        }
        self.add_sentinel
    }
}
<commit_msg>Fix some doc comments<commit_after>use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::PathBuf;
use std::str::FromStr;

use toml;

pub use bindgen::annotation::*;
pub use bindgen::rename::*;

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// A language type to generate bindings for.
#[derive(Debug, Clone, PartialEq)]
pub enum Language {
    Cxx,
    C,
}

/// A style of braces to use for generating code.
#[derive(Debug, Clone, PartialEq)]
pub enum Braces {
    SameLine,
    NextLine,
}

/// A type of layout to use when generating long lines of code.
#[derive(Debug, Clone, PartialEq)]
pub enum Layout {
    Horizontal,
    Vertical,
    Auto,
}

impl FromStr for Language {
    type Err = String;

    fn from_str(s: &str) -> Result<Language, Self::Err> {
        match s {
            "cxx" => Ok(Language::Cxx),
            "Cxx" => Ok(Language::Cxx),
            "CXX" => Ok(Language::Cxx),
            "cpp" => Ok(Language::Cxx),
            "Cpp" => Ok(Language::Cxx),
            "CPP" => Ok(Language::Cxx),
            "c++" => Ok(Language::Cxx),
            "C++" => Ok(Language::Cxx),
            "c" => Ok(Language::C),
            "C" => Ok(Language::C),
            _ => Err(format!("unrecognized Language: '{}'", s)),
        }
    }
}
impl FromStr for Braces {
    type Err = String;

    fn from_str(s: &str) -> Result<Braces, Self::Err> {
        match s {
            "SameLine" => Ok(Braces::SameLine),
            "same_line" => Ok(Braces::SameLine),
            "NextLine" => Ok(Braces::NextLine),
            "next_line" => Ok(Braces::NextLine),
            _ => Err(format!("unrecognized Braces: '{}'", s)),
        }
    }
}
impl FromStr for Layout {
    type Err = String;

    fn from_str(s: &str) -> Result<Layout, Self::Err> {
        match s {
            "Horizontal" => Ok(Layout::Horizontal),
            "horizontal" => Ok(Layout::Horizontal),
            "Vertical" => Ok(Layout::Vertical),
            "vertical" => Ok(Layout::Vertical),
            "Auto" => Ok(Layout::Auto),
            "auto" => Ok(Layout::Auto),
            _ => Err(format!("unrecognized Layout: '{}'", s)),
        }
    }
}

deserialize_enum_str!(Language);
deserialize_enum_str!(Braces);
deserialize_enum_str!(Layout);

/// A collection of settings to customize the generated bindings.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct Config {
    /// Optional text to output at the beginning of the file
    pub header: Option<String>,
    /// Optional text to output at the end of the file
    pub trailer: Option<String>,
    /// Option name to use for an include guard
    pub include_guard: Option<String>,
    /// Optional text to output at major sections to deter manual editing
    pub autogen_warning: Option<String>,
    /// Include a comment with the version of cbindgen used to generate the file
    pub include_version: bool,
    /// The style to use for braces
    pub braces: Braces,
    /// The preferred length of a line, used for auto breaking function arguments
    pub line_length: usize,
    /// The amount of spaces in a tab
    pub tab_width: usize,
    /// The language to output bindings for
    pub language: Language,
    /// The configuration options for functions
    #[serde(rename = "fn")]
    pub function: FunctionConfig,
    /// The configuration options for structs
    #[serde(rename = "struct")]
    pub structure: StructConfig,
    /// The configuration options for enums
    #[serde(rename = "enum")]
    pub enumeration: EnumConfig,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            header: None,
            trailer: None,
            include_guard: None,
            autogen_warning: None,
            include_version: true,
            braces: Braces::SameLine,
            line_length: 100,
            tab_width: 2,
            language: Language::Cxx,
            function: FunctionConfig::default(),
            structure: StructConfig::default(),
            enumeration: EnumConfig::default(),
        }
    }
}

/// Settings to apply to generated functions.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct FunctionConfig {
    /// Optional text to output before each function declaration
    pub prefix: Option<String>,
    /// Optional text to output after each function declaration
    pub postfix: Option<String>,
    /// The style to layout the args
    pub args: Layout,
    /// The rename rule to apply to function args
    pub rename_args: Option<RenameRule>,
}

impl Default for FunctionConfig {
    fn default() -> FunctionConfig {
        FunctionConfig {
            prefix: None,
            postfix: None,
            args: Layout::Auto,
            rename_args: None,
        }
    }
}

/// Settings to apply to generated structs.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct StructConfig {
    /// The rename rule to apply to the name of struct fields
    pub rename_fields: Option<RenameRule>,
    /// Whether to generate a piecewise equality operator
    pub derive_eq: bool,
    /// Whether to generate a piecewise inequality operator
    pub derive_neq: bool,
    /// Whether to generate a less than operator on structs with one field
    pub derive_lt: bool,
    /// Whether to generate a less than or equal to operator on structs with one field
    pub derive_lte: bool,
    /// Whether to generate a greater than operator on structs with one field
    pub derive_gt: bool,
    /// Whether to generate a greater than or equal to operator on structs with one field
    pub derive_gte: bool,
}

impl Default for StructConfig {
    fn default() -> StructConfig {
        StructConfig {
            rename_fields: None,
            derive_eq: false,
            derive_neq: false,
            derive_lt: false,
            derive_lte: false,
            derive_gt: false,
            derive_gte: false,
        }
    }
}

/// Settings to apply to generated enums.
#[derive( Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct EnumConfig {
    /// The rename rule to apply to the name of enum variants
    pub rename_variants: Option<RenameRule>,
    /// Whether to add a `Sentinel` value at the end of every enum
    /// This is useful in Gecko for IPC serialization
    pub add_sentinel: bool,
}

impl Default for EnumConfig {
    fn default() -> EnumConfig {
        EnumConfig {
            rename_variants: None,
            add_sentinel: false,
        }
    }
}

impl Config {
    pub fn from_file(file_name: &str) -> Result<Config, String> {
        fn read(file_name: &str) -> io::Result<String> {
            let file = File::open(file_name)?;
            let mut reader = BufReader::new(&file);
            let mut contents = String::new();
            reader.read_to_string(&mut contents)?;
            Ok(contents)
        }

        let config_text = read(file_name).unwrap();

        match toml::from_str::<Config>(&config_text) {
            Ok(x) => Ok(x),
            Err(e) => Err(format!("couldn't parse config file: {}", e)),
        }
    }

    pub fn from_root_or_default(root: &str) -> Config {
        let c = PathBuf::from(root).join("cbindgen.toml");

        if c.exists() {
            Config::from_file(c.to_str().unwrap()).unwrap()
        } else {
            Config::default()
        }
    }
}

impl FunctionConfig {
    pub fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
        if let Some(x) = annotations.atom("prefix") {
            return x;
        }
        self.prefix.clone()
    }

    pub fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
        if let Some(x) = annotations.atom("postfix") {
            return x;
        }
        self.postfix.clone()
    }
}

impl StructConfig {
    pub fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-eq") {
            return x;
        }
        self.derive_eq
    }
    pub fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-neq") {
            return x;
        }
        self.derive_neq
    }
    pub fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-lt") {
            return x;
        }
        self.derive_lt
    }
    pub fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-lte") {
            return x;
        }
        self.derive_lte
    }
    pub fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-gt") {
            return x;
        }
        self.derive_gt
    }
    pub fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("derive-gte") {
            return x;
        }
        self.derive_gte
    }
}

impl EnumConfig {
    pub fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
        if let Some(x) = annotations.bool("add-sentinel") {
            return x;
        }
        self.add_sentinel
    }
}
<|endoftext|>


<commit_before>use std::env;

#[allow(while_true)]
fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => {
            while true {
                println!("yes");
            }
        },
        _ => {
            while true {
                println!("{}", args[1]);
            }
        },
    }
}
<commit_msg>Update yes.rs<commit_after>use std::env;

#[allow(while_true)]
fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => {
            while true {
                println!("y");
            }
        },
        _ => {
            while true {
                println!("{}", args[1]);
            }
        },
    }
}
<|endoftext|>


<commit_before><commit_msg>[REFACTOR] Remove TryFrom<Vec<u8>> for Blake2bHash<commit_after><|endoftext|>


<commit_before>use std::url::Url;
use std::{cmp, mem, ptr};
use std::get_slice::GetSlice;
use std::io::*;
use std::process::Command;
use std::ops::DerefMut;
use std::syscall::SysError;
use std::syscall::ENOENT;
use std::to_num::ToNum;

use orbital::event::Event;
use orbital::Point;
use orbital::Size;

use self::display::Display;
use self::session::Session;
use self::window::Window;

pub mod display;
pub mod package;
pub mod session;
pub mod window;

pub static mut session_ptr: *mut Session = 0 as *mut Session;

/// A window resource
pub struct Resource {
    /// The window
    pub window: Box<Window>,
    /// Seek point
    pub seek: usize,
}

impl Resource {
    pub fn dup(&self) -> Result<Box<Resource>> {
        Ok(box Resource {
            window: Window::new(self.window.point,
                                self.window.size,
                                self.window.title.clone()),
            seek: self.seek,
        })
    }

    /// Return the url of this resource
    pub fn path(&self) -> Result<String> {
        Ok(format!("orbital:///{}/{}/{}/{}/{}",
                   self.window.point.x,
                   self.window.point.y,
                   self.window.size.width,
                   self.window.size.height,
                   self.window.title))
    }

    /// Read data to buffer
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        // Read events from window
        let mut i = 0;
        while buf.len() - i >= mem::size_of::<Event>() {
            match self.window.poll() {
                Some(event) => {
                    unsafe { ptr::write(buf.as_ptr().offset(i as isize) as *mut Event, event) };
                    i += mem::size_of::<Event>();
                }
                None => break,
            }
        }

        Ok(i)
    }

    /// Write to resource
    pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let content = &mut self.window.content;

        let size = cmp::min(content.size - self.seek, buf.len());
        unsafe {
            Display::copy_run(buf.as_ptr() as usize, content.offscreen + self.seek, size);
        }
        self.seek += size;

        Ok(size)
    }

    /// Seek
    pub fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        let end = self.window.content.size;

        self.seek = match pos {
            SeekFrom::Start(offset) => cmp::min(end as u64, cmp::max(0, offset)) as usize,
            SeekFrom::Current(offset) =>
                cmp::min(end as i64, cmp::max(0, self.seek as i64 + offset)) as usize,
            SeekFrom::End(offset) =>
                cmp::min(end as i64, cmp::max(0, end as i64 + offset)) as usize,
        };

        Ok(self.seek as u64)
    }

    /// Sync the resource, should flip
    pub fn sync(&mut self) -> Result<()> {
        self.window.redraw();
        Ok(())
    }
}

/// A window scheme
pub struct Scheme {
    pub session: Box<Session>,
    pub next_x: isize,
    pub next_y: isize,
}

impl Scheme {
    pub fn new() -> Box<Scheme> {
        println!("- Starting Orbital");
        println!("    Console: Press F1");
        println!("    Desktop: Press F2");
        let mut ret = box Scheme {
            session: Session::new(),
            next_x: 0,
            next_y: 0,
        };
        unsafe { session_ptr = ret.session.deref_mut() };
        ret
    }

    pub fn open(&mut self, url_str: &str, _: usize) -> Result<Box<Resource>> {
        // window://host/path/path/path is the path type we're working with.
        let url = Url::from_str(url_str);

        let host = url.host();
        if host.is_empty() {
            let path = url.path_parts();
            let mut pointx = match path.get(0) {
                Some(x) => x.to_num_signed(),
                None => 0,
            };
            let mut pointy = match path.get(1) {
                Some(y) => y.to_num_signed(),
                None => 0,
            };
            let size_width = match path.get(2) {
                Some(w) => w.to_num(),
                None => 100,
            };
            let size_height = match path.get(3) {
                Some(h) => h.to_num(),
                None => 100,
            };

            let mut title = match path.get(4) {
                Some(t) => t.clone(),
                None => String::new(),
            };
            for i in 5..path.len() {
                if let Some(t) = path.get(i) {
                    title = title + "/" + t;
                }
            }

            if pointx <= 0 || pointy <= 0 {
                if self.next_x > self.session.display.width as isize - size_width as isize {
                    self.next_x = 0;
                }
                self.next_x += 32;
                pointx = self.next_x as i32;

                if self.next_y > self.session.display.height as isize - size_height as isize {
                    self.next_y = 0;
                }
                self.next_y += 32;
                pointy = self.next_y as i32;
            }

            Ok(box Resource {
                window: Window::new(Point::new(pointx, pointy),
                                    Size::new(size_width, size_height),
                                    title),
                seek: 0,
            })
        } else if host == "launch" {
            let path = url.path();

            for package in self.session.packages.iter() {
                let mut accepted = false;
                for accept in package.accepts.iter() {
                    if (accept.starts_with('*') &&
                        path.ends_with(&accept.get_slice(Some(1), None))) ||
                       (accept.ends_with('*') &&
                        path.starts_with(&accept.get_slice(None, Some(accept.len() - 1)))) {
                        accepted = true;
                        break;
                    }
                }
                if accepted {
                    if Command::new(&package.binary).arg(&path).spawn_scheme().is_none() {
                        println!("{}: Failed to launch", package.binary);
                    }
                    break;
                }
            }

            Err(SysError::new(ENOENT))
        } else {
            Err(SysError::new(ENOENT))
        }
    }

    pub fn event(&mut self, event: &Event) {
        self.session.event(event);

        unsafe { self.session.redraw() };
    }
}

// TODO: This is a hack and it will go away
#[cold]
#[inline(never)]
#[no_mangle]
pub unsafe extern "C" fn _event(scheme: *mut Scheme, event: *const Event) {
    (*scheme).event(&*event);
}
<commit_msg>Fixes #439 - Launch binaries from file manager if they end in .bin<commit_after>use std::url::Url;
use std::{cmp, mem, ptr};
use std::get_slice::GetSlice;
use std::io::*;
use std::process::Command;
use std::ops::DerefMut;
use std::syscall::SysError;
use std::syscall::ENOENT;
use std::to_num::ToNum;

use orbital::event::Event;
use orbital::Point;
use orbital::Size;

use self::display::Display;
use self::session::Session;
use self::window::Window;

pub mod display;
pub mod package;
pub mod session;
pub mod window;

pub static mut session_ptr: *mut Session = 0 as *mut Session;

/// A window resource
pub struct Resource {
    /// The window
    pub window: Box<Window>,
    /// Seek point
    pub seek: usize,
}

impl Resource {
    pub fn dup(&self) -> Result<Box<Resource>> {
        Ok(box Resource {
            window: Window::new(self.window.point,
                                self.window.size,
                                self.window.title.clone()),
            seek: self.seek,
        })
    }

    /// Return the url of this resource
    pub fn path(&self) -> Result<String> {
        Ok(format!("orbital:///{}/{}/{}/{}/{}",
                   self.window.point.x,
                   self.window.point.y,
                   self.window.size.width,
                   self.window.size.height,
                   self.window.title))
    }

    /// Read data to buffer
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        // Read events from window
        let mut i = 0;
        while buf.len() - i >= mem::size_of::<Event>() {
            match self.window.poll() {
                Some(event) => {
                    unsafe { ptr::write(buf.as_ptr().offset(i as isize) as *mut Event, event) };
                    i += mem::size_of::<Event>();
                }
                None => break,
            }
        }

        Ok(i)
    }

    /// Write to resource
    pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let content = &mut self.window.content;

        let size = cmp::min(content.size - self.seek, buf.len());
        unsafe {
            Display::copy_run(buf.as_ptr() as usize, content.offscreen + self.seek, size);
        }
        self.seek += size;

        Ok(size)
    }

    /// Seek
    pub fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        let end = self.window.content.size;

        self.seek = match pos {
            SeekFrom::Start(offset) => cmp::min(end as u64, cmp::max(0, offset)) as usize,
            SeekFrom::Current(offset) =>
                cmp::min(end as i64, cmp::max(0, self.seek as i64 + offset)) as usize,
            SeekFrom::End(offset) =>
                cmp::min(end as i64, cmp::max(0, end as i64 + offset)) as usize,
        };

        Ok(self.seek as u64)
    }

    /// Sync the resource, should flip
    pub fn sync(&mut self) -> Result<()> {
        self.window.redraw();
        Ok(())
    }
}

/// A window scheme
pub struct Scheme {
    pub session: Box<Session>,
    pub next_x: isize,
    pub next_y: isize,
}

impl Scheme {
    pub fn new() -> Box<Scheme> {
        println!("- Starting Orbital");
        println!("    Console: Press F1");
        println!("    Desktop: Press F2");
        let mut ret = box Scheme {
            session: Session::new(),
            next_x: 0,
            next_y: 0,
        };
        unsafe { session_ptr = ret.session.deref_mut() };
        ret
    }

    pub fn open(&mut self, url_str: &str, _: usize) -> Result<Box<Resource>> {
        // window://host/path/path/path is the path type we're working with.
        let url = Url::from_str(url_str);

        let host = url.host();
        if host.is_empty() {
            let path = url.path_parts();
            let mut pointx = match path.get(0) {
                Some(x) => x.to_num_signed(),
                None => 0,
            };
            let mut pointy = match path.get(1) {
                Some(y) => y.to_num_signed(),
                None => 0,
            };
            let size_width = match path.get(2) {
                Some(w) => w.to_num(),
                None => 100,
            };
            let size_height = match path.get(3) {
                Some(h) => h.to_num(),
                None => 100,
            };

            let mut title = match path.get(4) {
                Some(t) => t.clone(),
                None => String::new(),
            };
            for i in 5..path.len() {
                if let Some(t) = path.get(i) {
                    title = title + "/" + t;
                }
            }

            if pointx <= 0 || pointy <= 0 {
                if self.next_x > self.session.display.width as isize - size_width as isize {
                    self.next_x = 0;
                }
                self.next_x += 32;
                pointx = self.next_x as i32;

                if self.next_y > self.session.display.height as isize - size_height as isize {
                    self.next_y = 0;
                }
                self.next_y += 32;
                pointy = self.next_y as i32;
            }

            Ok(box Resource {
                window: Window::new(Point::new(pointx, pointy),
                                    Size::new(size_width, size_height),
                                    title),
                seek: 0,
            })
        } else if host == "launch" {
            let path = url.path();

            if path.ends_with(".bin") {
                if Command::new(&path).spawn_scheme().is_none() {
                    println!("{}: Failed to launch", path);
                }
            } else {
                for package in self.session.packages.iter() {
                    let mut accepted = false;
                    for accept in package.accepts.iter() {
                        if (accept.starts_with('*') &&
                            path.ends_with(&accept.get_slice(Some(1), None))) ||
                           (accept.ends_with('*') &&
                            path.starts_with(&accept.get_slice(None, Some(accept.len() - 1)))) {
                            accepted = true;
                            break;
                        }
                    }
                    if accepted {
                        if Command::new(&package.binary).arg(&path).spawn_scheme().is_none() {
                            println!("{}: Failed to launch", package.binary);
                        }
                        break;
                    }
                }
            }

            Err(SysError::new(ENOENT))
        } else {
            Err(SysError::new(ENOENT))
        }
    }

    pub fn event(&mut self, event: &Event) {
        self.session.event(event);

        unsafe { self.session.redraw() };
    }
}

// TODO: This is a hack and it will go away
#[cold]
#[inline(never)]
#[no_mangle]
pub unsafe extern "C" fn _event(scheme: *mut Scheme, event: *const Event) {
    (*scheme).event(&*event);
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use]
extern crate failure;
extern crate ron;
extern crate tera;
extern crate tools;
extern crate walkdir;
extern crate heck;

use clap::{App, Arg, SubCommand};
use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
    process::Command,
};
use tools::{collect_tests, Test};

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

const GRAMMAR_DIR: &str = "./crates/libsyntax2/src/grammar";
const INLINE_TESTS_DIR: &str = "./crates/libsyntax2/tests/data/parser/inline";
const GRAMMAR: &str = "./crates/libsyntax2/src/grammar.ron";
const SYNTAX_KINDS: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs";
const SYNTAX_KINDS_TEMPLATE: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs.tera";
const AST: &str = "./crates/libsyntax2/src/ast/generated.rs";
const AST_TEMPLATE: &str = "./crates/libsyntax2/src/ast/generated.rs.tera";

fn main() -> Result<()> {
    let matches = App::new("tasks")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("verify")
                .long("--verify")
                .help("Verify that generated code is up-to-date")
                .global(true),
        )
        .subcommand(SubCommand::with_name("gen-kinds"))
        .subcommand(SubCommand::with_name("gen-tests"))
        .subcommand(SubCommand::with_name("install-code"))
        .get_matches();
    match matches.subcommand() {
        ("install-code", _) => install_code_extension()?,
        (name, Some(matches)) => run_gen_command(name, matches.is_present("verify"))?,
        _ => unreachable!(),
    }
    Ok(())
}

fn run_gen_command(name: &str, verify: bool) -> Result<()> {
    match name {
        "gen-kinds" => {
            update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?;
            update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?;
        },
        "gen-tests" => {
            gen_tests(verify)?
        },
        _ => unreachable!(),
    }
    Ok(())
}

fn update(path: &Path, contents: &str, verify: bool) -> Result<()> {
    match fs::read_to_string(path) {
        Ok(ref old_contents) if old_contents == contents => {
            return Ok(());
        }
        _ => (),
    }
    if verify {
        bail!("`{}` is not up-to-date", path.display());
    }
    eprintln!("updating {}", path.display());
    fs::write(path, contents)?;
    Ok(())
}

fn render_template(template: &str) -> Result<String> {
    let grammar: ron::value::Value = {
        let text = fs::read_to_string(GRAMMAR)?;
        ron::de::from_str(&text)?
    };
    let template = fs::read_to_string(template)?;
    let mut tera = tera::Tera::default();
    tera.add_raw_template("grammar", &template)
        .map_err(|e| format_err!("template error: {:?}", e))?;
    tera.register_global_function("concat", Box::new(concat));
    tera.register_filter("camel", |arg, _| {
        Ok(arg.as_str().unwrap().to_camel_case().into())
    });
    tera.register_filter("snake", |arg, _| {
        Ok(arg.as_str().unwrap().to_snake_case().into())
    });
    tera.register_filter("SCREAM", |arg, _| {
        Ok(arg.as_str().unwrap().to_shouty_snake_case().into())
    });
    let ret = tera
        .render("grammar", &grammar)
        .map_err(|e| format_err!("template error: {:?}", e))?;
    return Ok(ret);

    fn concat(args: HashMap<String, tera::Value>) -> tera::Result<tera::Value> {
        let mut elements = Vec::new();
        for &key in ["a", "b", "c"].iter() {
            let val = match args.get(key) {
                Some(val) => val,
                None => continue,
            };
            let val = val.as_array().unwrap();
            elements.extend(val.iter().cloned());
        }
        Ok(tera::Value::Array(elements))
    }
}

fn gen_tests(verify: bool) -> Result<()> {
    let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;

    let inline_tests_dir = Path::new(INLINE_TESTS_DIR);
    if !inline_tests_dir.is_dir() {
        fs::create_dir_all(inline_tests_dir)?;
    }
    let existing = existing_tests(inline_tests_dir)?;

    for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
        panic!("Test is deleted: {}", t);
    }

    let mut new_idx = existing.len() + 2;
    for (name, test) in tests {
        let path = match existing.get(&name) {
            Some((path, _test)) => path.clone(),
            None => {
                let file_name = format!("{:04}_{}.rs", new_idx, name);
                new_idx += 1;
                inline_tests_dir.join(file_name)
            }
        };
        update(&path, &test.text, verify)?;
    }
    Ok(())
}

fn tests_from_dir(dir: &Path) -> Result<HashMap<String, Test>> {
    let mut res = HashMap::new();
    for entry in ::walkdir::WalkDir::new(dir) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue;
        }
        if entry.path().extension().unwrap_or_default() != "rs" {
            continue;
        }
        let text = fs::read_to_string(entry.path())?;

        for (_, test) in collect_tests(&text) {
            if let Some(old_test) = res.insert(test.name.clone(), test) {
                bail!("Duplicate test: {}", old_test.name)
            }
        }
    }
    Ok(res)
}

fn existing_tests(dir: &Path) -> Result<HashMap<String, (PathBuf, Test)>> {
    let mut res = HashMap::new();
    for file in fs::read_dir(dir)? {
        let file = file?;
        let path = file.path();
        if path.extension().unwrap_or_default() != "rs" {
            continue;
        }
        let name = {
            let file_name = path.file_name().unwrap().to_str().unwrap();
            file_name[5..file_name.len() - 3].to_string()
        };
        let text = fs::read_to_string(&path)?;
        let test = Test {
            name: name.clone(),
            text,
        };
        match res.insert(name, (path, test)) {
            Some(old) => println!("Duplicate test: {:?}", old),
            None => (),
        }
    }
    Ok(res)
}

fn install_code_extension() -> Result<()> {
    run("cargo install --path crates/server --force", ".")?;
    run(r"npm install", "./code")?;
    run(r"./node_modules/vsce/out/vsce package", "./code")?;
    run(r"code --install-extension ./rcf-lsp-0.0.1.vsix", "./code")?;
    Ok(())
}

fn run(cmdline: &'static str, dir: &str) -> Result<()> {
    eprintln!("\nwill run: {}", cmdline);
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let project_dir = Path::new(manifest_dir).ancestors().nth(2).unwrap().join(dir);
    let mut args = cmdline.split_whitespace();
    let exec = args.next().unwrap();
    let status = Command::new(exec)
        .args(args)
        .current_dir(project_dir)
        .status()?;
    if !status.success() {
        bail!("`{}` exited with {}", cmdline, status);
    }
    Ok(())
}
<commit_msg>fix installation for windows<commit_after>extern crate clap;
#[macro_use]
extern crate failure;
extern crate ron;
extern crate tera;
extern crate tools;
extern crate walkdir;
extern crate heck;

use clap::{App, Arg, SubCommand};
use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
    process::Command,
};
use tools::{collect_tests, Test};

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

const GRAMMAR_DIR: &str = "./crates/libsyntax2/src/grammar";
const INLINE_TESTS_DIR: &str = "./crates/libsyntax2/tests/data/parser/inline";
const GRAMMAR: &str = "./crates/libsyntax2/src/grammar.ron";
const SYNTAX_KINDS: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs";
const SYNTAX_KINDS_TEMPLATE: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs.tera";
const AST: &str = "./crates/libsyntax2/src/ast/generated.rs";
const AST_TEMPLATE: &str = "./crates/libsyntax2/src/ast/generated.rs.tera";

fn main() -> Result<()> {
    let matches = App::new("tasks")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("verify")
                .long("--verify")
                .help("Verify that generated code is up-to-date")
                .global(true),
        )
        .subcommand(SubCommand::with_name("gen-kinds"))
        .subcommand(SubCommand::with_name("gen-tests"))
        .subcommand(SubCommand::with_name("install-code"))
        .get_matches();
    match matches.subcommand() {
        ("install-code", _) => install_code_extension()?,
        (name, Some(matches)) => run_gen_command(name, matches.is_present("verify"))?,
        _ => unreachable!(),
    }
    Ok(())
}

fn run_gen_command(name: &str, verify: bool) -> Result<()> {
    match name {
        "gen-kinds" => {
            update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?;
            update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?;
        },
        "gen-tests" => {
            gen_tests(verify)?
        },
        _ => unreachable!(),
    }
    Ok(())
}

fn update(path: &Path, contents: &str, verify: bool) -> Result<()> {
    match fs::read_to_string(path) {
        Ok(ref old_contents) if old_contents == contents => {
            return Ok(());
        }
        _ => (),
    }
    if verify {
        bail!("`{}` is not up-to-date", path.display());
    }
    eprintln!("updating {}", path.display());
    fs::write(path, contents)?;
    Ok(())
}

fn render_template(template: &str) -> Result<String> {
    let grammar: ron::value::Value = {
        let text = fs::read_to_string(GRAMMAR)?;
        ron::de::from_str(&text)?
    };
    let template = fs::read_to_string(template)?;
    let mut tera = tera::Tera::default();
    tera.add_raw_template("grammar", &template)
        .map_err(|e| format_err!("template error: {:?}", e))?;
    tera.register_global_function("concat", Box::new(concat));
    tera.register_filter("camel", |arg, _| {
        Ok(arg.as_str().unwrap().to_camel_case().into())
    });
    tera.register_filter("snake", |arg, _| {
        Ok(arg.as_str().unwrap().to_snake_case().into())
    });
    tera.register_filter("SCREAM", |arg, _| {
        Ok(arg.as_str().unwrap().to_shouty_snake_case().into())
    });
    let ret = tera
        .render("grammar", &grammar)
        .map_err(|e| format_err!("template error: {:?}", e))?;
    return Ok(ret);

    fn concat(args: HashMap<String, tera::Value>) -> tera::Result<tera::Value> {
        let mut elements = Vec::new();
        for &key in ["a", "b", "c"].iter() {
            let val = match args.get(key) {
                Some(val) => val,
                None => continue,
            };
            let val = val.as_array().unwrap();
            elements.extend(val.iter().cloned());
        }
        Ok(tera::Value::Array(elements))
    }
}

fn gen_tests(verify: bool) -> Result<()> {
    let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;

    let inline_tests_dir = Path::new(INLINE_TESTS_DIR);
    if !inline_tests_dir.is_dir() {
        fs::create_dir_all(inline_tests_dir)?;
    }
    let existing = existing_tests(inline_tests_dir)?;

    for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
        panic!("Test is deleted: {}", t);
    }

    let mut new_idx = existing.len() + 2;
    for (name, test) in tests {
        let path = match existing.get(&name) {
            Some((path, _test)) => path.clone(),
            None => {
                let file_name = format!("{:04}_{}.rs", new_idx, name);
                new_idx += 1;
                inline_tests_dir.join(file_name)
            }
        };
        update(&path, &test.text, verify)?;
    }
    Ok(())
}

fn tests_from_dir(dir: &Path) -> Result<HashMap<String, Test>> {
    let mut res = HashMap::new();
    for entry in ::walkdir::WalkDir::new(dir) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue;
        }
        if entry.path().extension().unwrap_or_default() != "rs" {
            continue;
        }
        let text = fs::read_to_string(entry.path())?;

        for (_, test) in collect_tests(&text) {
            if let Some(old_test) = res.insert(test.name.clone(), test) {
                bail!("Duplicate test: {}", old_test.name)
            }
        }
    }
    Ok(res)
}

fn existing_tests(dir: &Path) -> Result<HashMap<String, (PathBuf, Test)>> {
    let mut res = HashMap::new();
    for file in fs::read_dir(dir)? {
        let file = file?;
        let path = file.path();
        if path.extension().unwrap_or_default() != "rs" {
            continue;
        }
        let name = {
            let file_name = path.file_name().unwrap().to_str().unwrap();
            file_name[5..file_name.len() - 3].to_string()
        };
        let text = fs::read_to_string(&path)?;
        let test = Test {
            name: name.clone(),
            text,
        };
        match res.insert(name, (path, test)) {
            Some(old) => println!("Duplicate test: {:?}", old),
            None => (),
        }
    }
    Ok(res)
}

fn install_code_extension() -> Result<()> {
    run("cargo install --path crates/server --force", ".")?;
    if cfg!(windows) {
        run(r"cmd.exe /c npm.cmd install", "./code")?;
    } else {
        run(r"npm install", "./code")?;
    }
    run(r"node ./node_modules/vsce/out/vsce package", "./code")?;
    if cfg!(windows) {
        run(r"cmd.exe /c code.cmd --install-extension ./rcf-lsp-0.0.1.vsix", "./code")?;
    } else {
        run(r"code --install-extension ./rcf-lsp-0.0.1.vsix", "./code")?;
    }
    Ok(())
}

fn run(cmdline: &'static str, dir: &str) -> Result<()> {
    eprintln!("\nwill run: {}", cmdline);
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let project_dir = Path::new(manifest_dir).ancestors().nth(2).unwrap().join(dir);
    let mut args = cmdline.split_whitespace();
    let exec = args.next().unwrap();
    let status = Command::new(exec)
        .args(args)
        .current_dir(project_dir)
        .status()?;
    if !status.success() {
        bail!("`{}` exited with {}", cmdline, status);
    }
    Ok(())
}
<|endoftext|>


<commit_before>mod idt;

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("pop rsi // pop error code into rsi
                      mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

use vga_buffer::print_error;

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: DIVIDE BY ZERO\n{:#?}", *stack_frame));
    }
    loop {}
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
                                 (*stack_frame).instruction_pointer,
                                 *stack_frame));
    }
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame, error_code: u64) -> ! {
    use x86::controlregs;
    unsafe {
        print_error(format_args!("EXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
                                 controlregs::cr2(),
                                 PageFaultErrorCode::from_bits(error_code).unwrap(),
                                 *stack_frame));
    }
    loop {}
}
<commit_msg>Add missing rsi clobber in code as well<commit_after>mod idt;

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame) -> !)
                      : "rdi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                asm!("pop rsi // pop error code into rsi
                      mov rdi, rsp
                      sub rsp, 8 // align the stack pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64) -> !)
                      : "rdi","rsi" : "intel");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

use vga_buffer::print_error;

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: DIVIDE BY ZERO\n{:#?}", *stack_frame));
    }
    loop {}
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) -> ! {
    unsafe {
        print_error(format_args!("EXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
                                 (*stack_frame).instruction_pointer,
                                 *stack_frame));
    }
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame, error_code: u64) -> ! {
    use x86::controlregs;
    unsafe {
        print_error(format_args!("EXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
                                 controlregs::cr2(),
                                 PageFaultErrorCode::from_bits(error_code).unwrap(),
                                 *stack_frame));
    }
    loop {}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/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.

//! A wrapper around any Reader to treat it as an RNG.

use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(~[1,2,3,4,5,6,7,8]));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    priv reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read(v) {
            Ok(n) if n == v.len() => return,
            Ok(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \
                            read {} out of {} bytes.", n, v.len()),
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::io::MemReader;
    use std::cast;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u64, 2u64, 3u64];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u64(), 1);
        assert_eq!(rng.next_u64(), 2);
        assert_eq!(rng.next_u64(), 3);
    }
    #[test]
    fn test_reader_rng_u32() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u32, 2u32, 3u32];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u32(), 1);
        assert_eq!(rng.next_u32(), 2);
        assert_eq!(rng.next_u32(), 3);
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(~[]));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<commit_msg>auto merge of #13049 : alexcrichton/rust/io-fill, r=huonw<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/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.

//! A wrapper around any Reader to treat it as an RNG.

use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(~[1,2,3,4,5,6,7,8]));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    priv reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.fill(v) {
            Ok(()) => {}
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::io::MemReader;
    use std::cast;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u64, 2u64, 3u64];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u64(), 1);
        assert_eq!(rng.next_u64(), 2);
        assert_eq!(rng.next_u64(), 3);
    }
    #[test]
    fn test_reader_rng_u32() {
        // transmute from the target to avoid endianness concerns.
        let v = ~[1u32, 2u32, 3u32];
        let bytes: ~[u8] = unsafe {cast::transmute(v)};
        let mut rng = ReaderRng::new(MemReader::new(bytes));

        assert_eq!(rng.next_u32(), 1);
        assert_eq!(rng.next_u32(), 2);
        assert_eq!(rng.next_u32(), 3);
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(~[]));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<|endoftext|>