<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::{FontInstancePlatformOptions, FontKey, FontRenderMode};
use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection};
use dwrote;
use gamma_lut::{ColorLut, GammaLut};
use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph};
use internal_types::FastHashMap;
use std::sync::Arc;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: FastHashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

// DirectWrite is safe to use on multiple threads and non-shareable resources are
// all hidden inside their font context.
unsafe impl Send for FontContext {}

fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(
    render_mode: FontRenderMode,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_MEASURING_MODE {
    if let Some(FontInstancePlatformOptions {
        force_gdi_rendering: true,
        ..
    }) = options
    {
        return dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC;
    }

    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
    }
}

fn dwrite_render_mode(
    font_face: &dwrote::FontFace,
    render_mode: FontRenderMode,
    em_size: f32,
    measure_mode: dwrote::DWRITE_MEASURING_MODE,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_RENDERING_MODE {
    if let Some(FontInstancePlatformOptions {
        force_gdi_rendering: true,
        ..
    }) = options
    {
        return dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC;
    }

    let dwrite_render_mode = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => {
            font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
        }
    };

    if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
        // Outline mode is not supported
        return dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
    }

    dwrite_render_mode
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: FastHashMap::default(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn has_font(&self, font_key: &FontKey) -> bool {
        self.fonts.contains_key(font_key)
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: Arc<Vec<u8>>, index: u32) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(&**data) {
            let face = font_file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        self.fonts.remove(font_key);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &[u8], width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0 .. height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b,);
            }
            println!("");
        }
    }

    fn create_glyph_analysis(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font.font_key).unwrap();
        let glyph = key.index as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset {
            advanceOffset: 0.0,
            ascenderOffset: 0.0,
        };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: font.size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_measure_mode = dwrite_measure_mode(font.render_mode, font.platform_options);
        let dwrite_render_mode = dwrite_render_mode(
            face,
            font.render_mode,
            font.size.to_f32_px(),
            dwrite_measure_mode,
            font.platform_options,
        );

        let (x_offset, y_offset) = font.get_subpx_offset(key);
        let transform = Some(dwrote::DWRITE_MATRIX {
            m11: 1.0,
            m12: 0.0,
            m21: 0.0,
            m22: 1.0,
            dx: x_offset as f32,
            dy: y_offset as f32,
        });

        dwrote::GlyphRunAnalysis::create(
            &glyph_run,
            1.0,
            transform,
            dwrite_render_mode,
            dwrite_measure_mode,
            0.0,
            0.0,
        )
    }

    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
        let face = self.fonts.get(&font_key).unwrap();
        let indices = face.get_glyph_indices(&[ch as u32]);
        indices.first().map(|idx| *idx as u32)
    }

    // TODO: Pipe GlyphOptions into glyph_dimensions too
    pub fn get_glyph_dimensions(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font, key);

        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let face = self.fonts.get(&font.font_key).unwrap();
        face.get_design_glyph_metrics(&[key.index as u16], false)
            .first()
            .map(|metrics| {
                let em_size = font.size.to_f32_px() / 16.;
                let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32;
                let scaled_design_units_to_pixels = em_size / design_units_per_pixel;
                let advance = metrics.advanceWidth as f32 * scaled_design_units_to_pixels;

                GlyphDimensions {
                    left: bounds.left,
                    top: -bounds.top,
                    width,
                    height,
                    advance: advance,
                }
            })
    }

    // DWrite ClearType gives us values in RGB, but WR expects BGRA.
    fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Bitmap => {
                unreachable!("TODO: bitmap fonts");
            }
            FontRenderMode::Mono => {
                let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                for i in 0 .. pixels.len() {
                    let alpha = pixels[i];
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    // Only take the G channel, as its closest to D2D
                    let alpha = pixels[i * 3 + 1] as u8;
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
                    bgra_pixels[i * 4 + 3] = 0xff;
                }
                bgra_pixels
            }
        }
    }

    pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
        // TODO(gw): Support bitmap fonts in DWrite.
        false
    }

    pub fn prepare_font(font: &mut FontInstance) {
        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {
                // In mono/bitmap modes the color of the font is irrelevant.
                font.color = ColorU::new(255, 255, 255, 255);
                // Subpixel positioning is disabled in mono and bitmap modes.
                font.subpx_dir = SubpixelDirection::None;
            }
            FontRenderMode::Alpha => {
                font.color = font.color.luminance_color().quantize();
            }
            FontRenderMode::Subpixel => {
                font.color = font.color.quantize();
            }
        }
    }

    pub fn rasterize_glyph(
        &mut self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font, key);
        let texture_type = dwrite_texture_type(font.render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let pixels = analysis.create_alpha_texture(texture_type, bounds);
        let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode);

        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {}
            FontRenderMode::Alpha | FontRenderMode::Subpixel => {
                let lut_correction = match font.platform_options {
                    Some(option) => if option.force_gdi_rendering {
                        &self.gdi_gamma_lut
                    } else {
                        &self.gamma_lut
                    },
                    None => &self.gamma_lut,
                };

                lut_correction.preblend(&mut bgra_pixels, font.color);
            }
        }

        Some(RasterizedGlyph {
            left: bounds.left as f32,
            top: -bounds.top as f32,
            width,
            height,
            scale: 1.0,
            format: GlyphFormat::from(font.render_mode),
            bytes: bgra_pixels,
        })
    }
}
<commit_msg>Auto merge of #2038 - lsalzman:dwrite-embedded-bitmaps, r=glennw<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::{FontInstancePlatformOptions, FontKey, FontRenderMode};
use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection};
use dwrote;
use gamma_lut::{ColorLut, GammaLut};
use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph};
use internal_types::FastHashMap;
use std::sync::Arc;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: FastHashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

// DirectWrite is safe to use on multiple threads and non-shareable resources are
// all hidden inside their font context.
unsafe impl Send for FontContext {}

fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_TEXTURE_ALIASED_1x1,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(
    render_mode: FontRenderMode,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_MEASURING_MODE {
    let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
        options.unwrap_or_default();
    if force_gdi_rendering || use_embedded_bitmap {
        return dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC;
    }

    match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL,
    }
}

fn dwrite_render_mode(
    font_face: &dwrote::FontFace,
    render_mode: FontRenderMode,
    em_size: f32,
    measure_mode: dwrote::DWRITE_MEASURING_MODE,
    options: Option<FontInstancePlatformOptions>,
) -> dwrote::DWRITE_RENDERING_MODE {
    let FontInstancePlatformOptions { force_gdi_rendering, use_embedded_bitmap, .. } =
        options.unwrap_or_default();

    let dwrite_render_mode = match render_mode {
        FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha | FontRenderMode::Subpixel => {
            if force_gdi_rendering || use_embedded_bitmap {
                dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC
            } else {
                font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
            }
        }
    };

    if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
        // Outline mode is not supported
        return dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
    }

    dwrite_render_mode
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: FastHashMap::default(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn has_font(&self, font_key: &FontKey) -> bool {
        self.fonts.contains_key(font_key)
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: Arc<Vec<u8>>, index: u32) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(&**data) {
            let face = font_file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return;
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        self.fonts.remove(font_key);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &[u8], width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0 .. height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b,);
            }
            println!("");
        }
    }

    fn create_glyph_analysis(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font.font_key).unwrap();
        let glyph = key.index as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset {
            advanceOffset: 0.0,
            ascenderOffset: 0.0,
        };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: font.size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_measure_mode = dwrite_measure_mode(font.render_mode, font.platform_options);
        let dwrite_render_mode = dwrite_render_mode(
            face,
            font.render_mode,
            font.size.to_f32_px(),
            dwrite_measure_mode,
            font.platform_options,
        );

        let (x_offset, y_offset) = font.get_subpx_offset(key);
        let transform = Some(dwrote::DWRITE_MATRIX {
            m11: 1.0,
            m12: 0.0,
            m21: 0.0,
            m22: 1.0,
            dx: x_offset as f32,
            dy: y_offset as f32,
        });

        dwrote::GlyphRunAnalysis::create(
            &glyph_run,
            1.0,
            transform,
            dwrite_render_mode,
            dwrite_measure_mode,
            0.0,
            0.0,
        )
    }

    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
        let face = self.fonts.get(&font_key).unwrap();
        let indices = face.get_glyph_indices(&[ch as u32]);
        indices.first().map(|idx| *idx as u32)
    }

    // TODO: Pipe GlyphOptions into glyph_dimensions too
    pub fn get_glyph_dimensions(
        &self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font, key);

        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let face = self.fonts.get(&font.font_key).unwrap();
        face.get_design_glyph_metrics(&[key.index as u16], false)
            .first()
            .map(|metrics| {
                let em_size = font.size.to_f32_px() / 16.;
                let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32;
                let scaled_design_units_to_pixels = em_size / design_units_per_pixel;
                let advance = metrics.advanceWidth as f32 * scaled_design_units_to_pixels;

                GlyphDimensions {
                    left: bounds.left,
                    top: -bounds.top,
                    width,
                    height,
                    advance: advance,
                }
            })
    }

    // DWrite ClearType gives us values in RGB, but WR expects BGRA.
    fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Bitmap => {
                unreachable!("TODO: bitmap fonts");
            }
            FontRenderMode::Mono => {
                let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                for i in 0 .. pixels.len() {
                    let alpha = pixels[i];
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    // Only take the G channel, as its closest to D2D
                    let alpha = pixels[i * 3 + 1] as u8;
                    bgra_pixels[i * 4 + 0] = alpha;
                    bgra_pixels[i * 4 + 1] = alpha;
                    bgra_pixels[i * 4 + 2] = alpha;
                    bgra_pixels[i * 4 + 3] = alpha;
                }
                bgra_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0 .. length {
                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
                    bgra_pixels[i * 4 + 3] = 0xff;
                }
                bgra_pixels
            }
        }
    }

    pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
        // TODO(gw): Support bitmap fonts in DWrite.
        false
    }

    pub fn prepare_font(font: &mut FontInstance) {
        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {
                // In mono/bitmap modes the color of the font is irrelevant.
                font.color = ColorU::new(255, 255, 255, 255);
                // Subpixel positioning is disabled in mono and bitmap modes.
                font.subpx_dir = SubpixelDirection::None;
            }
            FontRenderMode::Alpha => {
                font.color = font.color.luminance_color().quantize();
            }
            FontRenderMode::Subpixel => {
                font.color = font.color.quantize();
            }
        }
    }

    pub fn rasterize_glyph(
        &mut self,
        font: &FontInstance,
        key: &GlyphKey,
    ) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font, key);
        let texture_type = dwrite_texture_type(font.render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;

        // Alpha texture bounds can sometimes return an empty rect
        // Such as for spaces
        if width == 0 || height == 0 {
            return None;
        }

        let pixels = analysis.create_alpha_texture(texture_type, bounds);
        let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode);

        match font.render_mode {
            FontRenderMode::Mono | FontRenderMode::Bitmap => {}
            FontRenderMode::Alpha | FontRenderMode::Subpixel => {
                let lut_correction = match font.platform_options {
                    Some(option) => if option.force_gdi_rendering {
                        &self.gdi_gamma_lut
                    } else {
                        &self.gamma_lut
                    },
                    None => &self.gamma_lut,
                };

                lut_correction.preblend(&mut bgra_pixels, font.color);
            }
        }

        Some(RasterizedGlyph {
            left: bounds.left as f32,
            top: -bounds.top as f32,
            width,
            height,
            scale: 1.0,
            format: GlyphFormat::from(font.render_mode),
            bytes: bgra_pixels,
        })
    }
}
<|endoftext|>


<commit_before>use crate::cargo::TestBinary;
#[cfg(ptrace_supported)]
use crate::ptrace_control::*;
#[cfg(ptrace_supported)]
use crate::statemachine::ProcessInfo;
use crate::statemachine::TracerAction;
use crate::traces::{Location, TraceMap};
use chrono::{offset::Local, SecondsFormat};
#[cfg(ptrace_supported)]
use nix::libc::*;
#[cfg(ptrace_supported)]
use nix::sys::{signal::Signal, wait::WaitStatus};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashSet;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::time::Instant;
use tracing::{info, warn};

#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Event {
    ConfigLaunch(String),
    BinaryLaunch(TestBinary),
    Trace(TraceEvent),
    Marker(Option<()>),
}

#[derive(Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct EventWrapper {
    #[serde(flatten)]
    event: Event,
    // The time this was created in seconds
    created: f64,
}

impl EventWrapper {
    fn new(event: Event, since: Instant) -> Self {
        let created = Instant::now().duration_since(since).as_secs_f64();
        Self { event, created }
    }
}

#[derive(Clone, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct TraceEvent {
    pid: Option<i64>,
    child: Option<i64>,
    signal: Option<String>,
    addr: Option<u64>,
    return_val: Option<i64>,
    location: Option<Location>,
    description: String,
}

impl TraceEvent {
    #[cfg(target_os = "linux")]
    pub(crate) fn new_from_action(action: &TracerAction<ProcessInfo>) -> Self {
        match action {
            TracerAction::TryContinue(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                signal: t.signal.map(|x| x.to_string()),
                description: "Try continue child".to_string(),
                ..Default::default()
            },
            TracerAction::Continue(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                signal: t.signal.map(|x| x.to_string()),
                description: "Continue child".to_string(),
                ..Default::default()
            },
            TracerAction::Step(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                description: "Step child".to_string(),
                ..Default::default()
            },
            TracerAction::Detach(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                description: "Detach child".to_string(),
                ..Default::default()
            },
            TracerAction::Nothing => TraceEvent {
                description: "Do nothing".to_string(),
                ..Default::default()
            },
        }
    }

    #[cfg(target_os = "linux")]
    pub(crate) fn new_from_wait(wait: &WaitStatus, offset: u64, traces: &TraceMap) -> Self {
        let pid = wait.pid().map(|p| p.as_raw().into());
        let mut event = TraceEvent {
            pid,
            ..Default::default()
        };
        match wait {
            WaitStatus::Exited(_, i) => {
                event.description = "Exited".to_string();
                event.return_val = Some((*i).into());
            }
            WaitStatus::Signaled(_, sig, _) => {
                event.signal = Some(sig.to_string());
                event.description = "Signaled".to_string();
            }
            WaitStatus::Stopped(c, sig) => {
                event.signal = Some(sig.to_string());
                if *sig == Signal::SIGTRAP {
                    event.description = "Stopped".to_string();
                    event.addr = current_instruction_pointer(*c).ok().map(|x| (x - 1) as u64);
                    if let Some(addr) = event.addr {
                        event.location = traces.get_location(addr - offset);
                    }
                } else {
                    event.description = "Non-trace stop".to_string();
                }
            }
            WaitStatus::PtraceEvent(pid, sig, val) => {
                event.signal = Some(sig.to_string());
                match *val {
                    PTRACE_EVENT_CLONE => {
                        event.description = "Ptrace Clone".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_FORK => {
                        event.description = "Ptrace fork".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_VFORK => {
                        event.description = "Ptrace vfork".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_EXEC => {
                        event.description = "Ptrace exec".to_string();
                    }
                    PTRACE_EVENT_EXIT => {
                        event.description = "Ptrace exit".to_string();
                    }
                    _ => {
                        event.description = "Ptrace unknown event".to_string();
                    }
                }
            }
            WaitStatus::Continued(_) => {
                event.description = "Continued".to_string();
            }
            WaitStatus::StillAlive => {
                event.description = "StillAlive".to_string();
            }
            WaitStatus::PtraceSyscall(_) => {
                event.description = "PtraceSyscall".to_string();
            }
        }
        event
    }
}

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct EventLog {
    events: RefCell<Vec<EventWrapper>>,
    #[serde(skip)]
    start: Option<Instant>,
    manifest_paths: HashSet<PathBuf>,
}

impl EventLog {
    pub fn new(manifest_paths: HashSet<PathBuf>) -> Self {
        Self {
            events: RefCell::new(vec![]),
            start: Some(Instant::now()),
            manifest_paths,
        }
    }

    pub fn push_binary(&self, binary: TestBinary) {
        self.events.borrow_mut().push(EventWrapper::new(
            Event::BinaryLaunch(binary),
            self.start.unwrap(),
        ));
    }

    pub fn push_trace(&self, event: TraceEvent) {
        self.events
            .borrow_mut()
            .push(EventWrapper::new(Event::Trace(event), self.start.unwrap()));
    }

    pub fn push_config(&self, name: String) {
        self.events.borrow_mut().push(EventWrapper::new(
            Event::ConfigLaunch(name),
            self.start.unwrap(),
        ));
    }

    pub fn push_marker(&self) {
        // Prevent back to back markers when we spend a lot of time waiting on events
        if self
            .events
            .borrow()
            .last()
            .filter(|x| matches!(x.event, Event::Marker(_)))
            .is_none()
        {
            self.events
                .borrow_mut()
                .push(EventWrapper::new(Event::Marker(None), self.start.unwrap()));
        }
    }
}

impl Drop for EventLog {
    fn drop(&mut self) {
        let fname = format!(
            "tarpaulin_{}.json",
            Local::now().to_rfc3339_opts(SecondsFormat::Secs, false)
        );
        let path = Path::new(&fname);
        info!("Serializing tarpaulin debug log to {}", path.display());
        if let Ok(output) = File::create(path) {
            if let Err(e) = serde_json::to_writer(output, self) {
                warn!("Failed to serialise or write result: {}", e);
            }
        } else {
            warn!("Failed to create log file");
        }
    }
}
<commit_msg>Fix last cfg<commit_after>use crate::cargo::TestBinary;
#[cfg(ptrace_supported)]
use crate::ptrace_control::*;
#[cfg(ptrace_supported)]
use crate::statemachine::ProcessInfo;
use crate::statemachine::TracerAction;
use crate::traces::{Location, TraceMap};
use chrono::{offset::Local, SecondsFormat};
#[cfg(ptrace_supported)]
use nix::libc::*;
#[cfg(ptrace_supported)]
use nix::sys::{signal::Signal, wait::WaitStatus};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashSet;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::time::Instant;
use tracing::{info, warn};

#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Event {
    ConfigLaunch(String),
    BinaryLaunch(TestBinary),
    Trace(TraceEvent),
    Marker(Option<()>),
}

#[derive(Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct EventWrapper {
    #[serde(flatten)]
    event: Event,
    // The time this was created in seconds
    created: f64,
}

impl EventWrapper {
    fn new(event: Event, since: Instant) -> Self {
        let created = Instant::now().duration_since(since).as_secs_f64();
        Self { event, created }
    }
}

#[derive(Clone, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct TraceEvent {
    pid: Option<i64>,
    child: Option<i64>,
    signal: Option<String>,
    addr: Option<u64>,
    return_val: Option<i64>,
    location: Option<Location>,
    description: String,
}

impl TraceEvent {
    #[cfg(target_os = "linux")]
    pub(crate) fn new_from_action(action: &TracerAction<ProcessInfo>) -> Self {
        match action {
            TracerAction::TryContinue(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                signal: t.signal.map(|x| x.to_string()),
                description: "Try continue child".to_string(),
                ..Default::default()
            },
            TracerAction::Continue(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                signal: t.signal.map(|x| x.to_string()),
                description: "Continue child".to_string(),
                ..Default::default()
            },
            TracerAction::Step(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                description: "Step child".to_string(),
                ..Default::default()
            },
            TracerAction::Detach(t) => TraceEvent {
                pid: Some(t.pid.as_raw().into()),
                description: "Detach child".to_string(),
                ..Default::default()
            },
            TracerAction::Nothing => TraceEvent {
                description: "Do nothing".to_string(),
                ..Default::default()
            },
        }
    }

    #[cfg(ptrace_supported)]
    pub(crate) fn new_from_wait(wait: &WaitStatus, offset: u64, traces: &TraceMap) -> Self {
        let pid = wait.pid().map(|p| p.as_raw().into());
        let mut event = TraceEvent {
            pid,
            ..Default::default()
        };
        match wait {
            WaitStatus::Exited(_, i) => {
                event.description = "Exited".to_string();
                event.return_val = Some((*i).into());
            }
            WaitStatus::Signaled(_, sig, _) => {
                event.signal = Some(sig.to_string());
                event.description = "Signaled".to_string();
            }
            WaitStatus::Stopped(c, sig) => {
                event.signal = Some(sig.to_string());
                if *sig == Signal::SIGTRAP {
                    event.description = "Stopped".to_string();
                    event.addr = current_instruction_pointer(*c).ok().map(|x| (x - 1) as u64);
                    if let Some(addr) = event.addr {
                        event.location = traces.get_location(addr - offset);
                    }
                } else {
                    event.description = "Non-trace stop".to_string();
                }
            }
            WaitStatus::PtraceEvent(pid, sig, val) => {
                event.signal = Some(sig.to_string());
                match *val {
                    PTRACE_EVENT_CLONE => {
                        event.description = "Ptrace Clone".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_FORK => {
                        event.description = "Ptrace fork".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_VFORK => {
                        event.description = "Ptrace vfork".to_string();
                        if *sig == Signal::SIGTRAP {
                            event.child = get_event_data(*pid).ok();
                        }
                    }
                    PTRACE_EVENT_EXEC => {
                        event.description = "Ptrace exec".to_string();
                    }
                    PTRACE_EVENT_EXIT => {
                        event.description = "Ptrace exit".to_string();
                    }
                    _ => {
                        event.description = "Ptrace unknown event".to_string();
                    }
                }
            }
            WaitStatus::Continued(_) => {
                event.description = "Continued".to_string();
            }
            WaitStatus::StillAlive => {
                event.description = "StillAlive".to_string();
            }
            WaitStatus::PtraceSyscall(_) => {
                event.description = "PtraceSyscall".to_string();
            }
        }
        event
    }
}

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct EventLog {
    events: RefCell<Vec<EventWrapper>>,
    #[serde(skip)]
    start: Option<Instant>,
    manifest_paths: HashSet<PathBuf>,
}

impl EventLog {
    pub fn new(manifest_paths: HashSet<PathBuf>) -> Self {
        Self {
            events: RefCell::new(vec![]),
            start: Some(Instant::now()),
            manifest_paths,
        }
    }

    pub fn push_binary(&self, binary: TestBinary) {
        self.events.borrow_mut().push(EventWrapper::new(
            Event::BinaryLaunch(binary),
            self.start.unwrap(),
        ));
    }

    pub fn push_trace(&self, event: TraceEvent) {
        self.events
            .borrow_mut()
            .push(EventWrapper::new(Event::Trace(event), self.start.unwrap()));
    }

    pub fn push_config(&self, name: String) {
        self.events.borrow_mut().push(EventWrapper::new(
            Event::ConfigLaunch(name),
            self.start.unwrap(),
        ));
    }

    pub fn push_marker(&self) {
        // Prevent back to back markers when we spend a lot of time waiting on events
        if self
            .events
            .borrow()
            .last()
            .filter(|x| matches!(x.event, Event::Marker(_)))
            .is_none()
        {
            self.events
                .borrow_mut()
                .push(EventWrapper::new(Event::Marker(None), self.start.unwrap()));
        }
    }
}

impl Drop for EventLog {
    fn drop(&mut self) {
        let fname = format!(
            "tarpaulin_{}.json",
            Local::now().to_rfc3339_opts(SecondsFormat::Secs, false)
        );
        let path = Path::new(&fname);
        info!("Serializing tarpaulin debug log to {}", path.display());
        if let Ok(output) = File::create(path) {
            if let Err(e) = serde_json::to_writer(output, self) {
                warn!("Failed to serialise or write result: {}", e);
            }
        } else {
            warn!("Failed to create log file");
        }
    }
}
<|endoftext|>


<commit_before>mod score;
pub mod consts;

pub use self::score::*;
<commit_msg>Add fuzzy::eq(a, b) function<commit_after>mod score;
pub mod consts;

pub use self::score::*;

/// Compares two characters case-insensitively
///
/// # Examples
///
/// ```
/// assert!(rff::fuzzy::eq('a', 'A'));
/// ```
pub fn eq(a: char, b: char) -> bool {
    a.to_uppercase().eq(b.to_uppercase())
}

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

    #[test]
    fn test_eq() {
        assert!(eq('a', 'A'));
        assert!(eq('山', '山'));
        assert!(!eq('a', 'b'));
    }
}
<|endoftext|>


<commit_before>extern crate rlibc;

use std::default::Default;
use std::iter::{Chain, range_inclusive};
use std::mem;
use std::slice;

fn vec_copy<T>(v: &mut Vec<T>, to: uint, from: uint, n: uint) {
  unsafe {
    let p_to = v.as_mut_ptr().offset(to as int);
    let p_from = v.as_ptr().offset(from as int);
    rlibc::memcpy(p_to as *mut u8, p_from as *const u8, n * mem::size_of::<T>());
  }
}

/// Circular bounded queue.
pub struct Queue<T> {
  pub contents: Vec<T>,
  /// index in `contents` the queue starts at
  pub head: uint,
  /// index in `contents` to place the next element at
  pub tail: uint,
  /// number of elements used
  pub length: uint,
}

impl<T: Clone> Queue<T> {
  pub fn new(capacity: uint) -> Queue<T> {
    Queue {
      contents: Vec::with_capacity(capacity),
      head: 0,
      tail: 0,
      length: 0,
    }
  }

  pub fn push(&mut self, t: T) {
    assert!(
      self.length < self.contents.capacity(),
      "Bounded queue (capacity {}) exceeded",
      self.contents.capacity()
    );

    if self.contents.len() < self.contents.capacity() {
      self.contents.push(t);
    } else {
      *self.contents.get_mut(self.tail) = t;
    }

    self.tail = (self.tail + 1) % self.contents.capacity();
    self.length += 1;
  }

  pub fn push_all<'a, I: Iterator<T>>(&mut self, ts: I) {
    let mut ts = ts;
    for t in ts {
      self.push(t);
    }
  }

  pub fn pop(&mut self, count: uint) {
    assert!(count <= self.length);
    self.head = (self.head + count) % self.contents.capacity();
    self.length -= count;
  }

  pub fn is_empty(&self) -> bool {
    self.length == 0
  }

  /// Swap `count` elements from `idx` with the last `count` elements of the
  /// queue, then drop the last `count` elements.
  /// The ordering amongst those `count` elements is maintained.
  pub fn swap_remove(&mut self, idx: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;

    assert!(idx <= self.length);

    self.tail = (self.tail + self.contents.capacity() - count) % self.contents.capacity();

    if idx < self.length {
      assert!(
        idx + count <= self.length,
        "Queue::swap_remove in overlapping regions"
      );

      let idx = idx + self.head;

      // At this point, we have a guarantee that the regions do not overlap.
      // Therefore, either the copy-from or copy-to regions might be broken up
      // by the end of the vector, but not both.

      let buffer_wrap_point = self.contents.capacity() - count;
      if idx > buffer_wrap_point {
        assert!(self.contents.len() == self.contents.capacity());

        // copy TO an area of the queue that crosses the end of the buffer.

        let count1 = self.contents.capacity() - idx;
        vec_copy(&mut self.contents, idx, self.tail, count1);
        let count2 = count - count1;
        vec_copy(&mut self.contents, 0, self.tail + count1, count2);
      } else if self.tail > buffer_wrap_point {
        assert!(self.contents.len() == self.contents.capacity());

        // copy FROM an area of the queue that crosses the end of the buffer.

        let count1 = self.contents.capacity() - self.tail;
        vec_copy(&mut self.contents, idx, self.tail, count1);
        let count2 = count - count1;
        vec_copy(&mut self.contents, idx + count1, 0, count2);
      } else {
        vec_copy(&mut self.contents, idx, self.tail, count);
      }
    }
  }

  pub fn len(&self) -> uint {
    self.length
  }

  #[allow(dead_code)]
  pub fn clear(&mut self) {
    self.contents.clear();
    self.head = 0;
    self.tail = 0;
    self.length = 0;
  }

  pub fn iter<'a>(&'a self, low: uint, high: uint) -> QueueItems<'a, T> {
    let (l, h) = self.slices(low, high);
    QueueItems { inner: l.iter().chain(h.iter()) }
  }

  pub fn slices<'a>(&'a self, low: uint, high: uint) -> (&'a [T], &'a [T]) {
    assert!(low <= high);
    assert!(low <= self.length);
    assert!(high <= self.length);
    let (l, h) =
      if low == high {
        (Default::default(), Default::default())
      } else {
        let head = (self.head + low) % self.contents.capacity();
        let tail = (self.head + high) % self.contents.capacity();
        if head < tail {
          (self.contents.slice(head, tail), Default::default())
        } else {
          assert!(self.contents.len() == self.contents.capacity());
          (self.contents.slice(head, self.contents.capacity()), self.contents.slice(0, tail))
        }
      };
    assert!(l.len() + h.len() == high - low);
    (l, h)
  }
}

#[test]
fn push_then_slice() {
  let elems: Vec<int> = Vec::from_slice([1, 2, 3]);
  let mut q = Queue::new(32);
  q.push_all(elems.iter());
  assert!(q.len() == elems.len());
  let (l, h) = q.slices(0, q.len() - 1);
  assert!(l.len() + h.len() == elems.len() - 1);
  for (i, elem) in l.iter().enumerate() {
    assert!(**elem == elems[i]);
  }
  for (i, elem) in h.iter().enumerate() {
    assert!(**elem == elems[i + l.len()]);
  }
}

#[test]
fn push_then_pop() {
  let popped_pushes: Vec<int> = Vec::from_slice([1, 2, 3]);
  let more_pushes: Vec<int> = Vec::from_slice([4, 5]);
  let mut q = Queue::new(32);
  q.push_all(popped_pushes.iter());
  q.push_all(more_pushes.iter());
  assert!(q.len() == popped_pushes.len() + more_pushes.len());
  q.pop(popped_pushes.len());
  assert!(q.len() == more_pushes.len());
  let (l, h) = q.slices(0, q.len());
  assert!(l.len() + h.len() == more_pushes.len());
  for (i, elem) in l.iter().enumerate() {
    assert!(**elem == more_pushes[i]);
  }
  for (i, elem) in h.iter().enumerate() {
    assert!(**elem == more_pushes[i + l.len()]);
  }
}

#[test]
fn wrapped_pushes() {
  static capacity: uint = 32;
  let popped_pushes = Vec::from_elem(capacity / 2, 0i);
  let more_pushes: Vec<int> = range_inclusive(1, capacity as int).collect();
  let mut q: Queue<int> = Queue::new(capacity);
  q.push_all(popped_pushes.iter().map(|&x| x));
  q.pop(popped_pushes.len());
  q.push_all(more_pushes.iter().map(|&x| x));
  assert!(q.len() == more_pushes.len());
  let (l, h) = q.slices(0, q.len());
  assert!(l.len() + h.len() == more_pushes.len());
  assert!(h.len() > 0);
  for (x, y) in l.iter().chain(h.iter()).zip(more_pushes.iter()) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_simple() {
  let mut q: Queue<int> = Queue::new(32);
  q.push_all([1,2,3,4,7,8,5,6i].iter().map(|&x| x));
  q.swap_remove(4, 2);

  let i = q.iter(0, q.len());
  let elems = [1,2,3,4,5,6i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn push_swap_remove_push() {
  let mut q: Queue<int> = Queue::new(32);
  q.push_all([1, 9i].iter().map(|&x| x));
  q.swap_remove(1, 1);
  q.push_all([2, 3, 4, 5i].iter().map(|&x| x));

  let elems = [1, 2, 3, 4, 5i];
  let i = q.iter(0, q.len());
  let mut count = 0;
  for (i, &x) in i.enumerate() {
    assert!(i < elems.len());
    assert_eq!(x, elems[i]);
    count += 1;
  }
  assert!(count == q.len());
  assert!(count == elems.len());
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_end() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [11, 12i];
  let elems = [1,2,3,4,5,6,7,8i];

  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all(elems.iter().map(|&x| x));
  q.swap_remove(4, 4);
  assert!(q.len() == 4);

  let i = q.iter(0, q.len());
  let mut count = 0;
  for (i, &x) in i.enumerate() {
    assert!(i < elems.len());
    assert!(x == elems[i]);
    count += 1;
  }
  assert!(count == q.len());
}

// TODO: clean up this test, de-duplicate, etc.
#[test]
fn swap_remove_to_broken() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [9,9,9,9i];
  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all([1,2,3,7,8,6,4,5i].iter().map(|&x| x));
  q.swap_remove(3, 2);

  let i = q.iter(0, q.len());
  let elems = [1,2,3,4,5,6i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_from_broken() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [9,9,9,9i];
  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all([4,5,6,1,2,3i].iter().map(|&x| x));
  q.swap_remove(0, 3);

  let i = q.iter(0, q.len());
  let elems = [1,2,3i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
fn vec_copy_test() {
  let mut v = Vec::from_slice([1,2,3,4,5i]);
  vec_copy(&mut v, 1, 3, 2);
  assert_eq!(v, Vec::from_slice([1, 4, 5, 4, 5i]));
}

pub struct QueueItems<'a, T> { inner: Chain<slice::Items<'a, T>, slice::Items<'a, T>> }

impl<'a, T> Iterator<&'a T> for QueueItems<'a, T> {
  fn next(&mut self) -> Option<&'a T> { self.inner.next() }
  fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}
<commit_msg>fix for Queue when combining pushes and swap_removes<commit_after>extern crate rlibc;

use std::default::Default;
use std::iter::{Chain, range_inclusive};
use std::mem;
use std::slice;

fn vec_copy<T>(v: &mut Vec<T>, to: uint, from: uint, n: uint) {
  unsafe {
    let p_to = v.as_mut_ptr().offset(to as int);
    let p_from = v.as_ptr().offset(from as int);
    rlibc::memcpy(p_to as *mut u8, p_from as *const u8, n * mem::size_of::<T>());
  }
}

/// Circular bounded queue.
pub struct Queue<T> {
  pub contents: Vec<T>,
  /// index in `contents` the queue starts at
  pub head: uint,
  /// index in `contents` to place the next element at
  pub tail: uint,
  /// number of elements used
  pub length: uint,
}

impl<T: Clone> Queue<T> {
  pub fn new(capacity: uint) -> Queue<T> {
    Queue {
      contents: Vec::with_capacity(capacity),
      head: 0,
      tail: 0,
      length: 0,
    }
  }

  pub fn push(&mut self, t: T) {
    assert!(
      self.length < self.contents.capacity(),
      "Bounded queue (capacity {}) exceeded",
      self.contents.capacity()
    );

    if self.tail >= self.contents.len() {
      assert!(self.contents.len() < self.contents.capacity());
      self.contents.push(t);
    } else {
      *self.contents.get_mut(self.tail) = t;
    }

    self.tail = (self.tail + 1) % self.contents.capacity();
    self.length += 1;
  }

  pub fn push_all<'a, I: Iterator<T>>(&mut self, ts: I) {
    let mut ts = ts;
    for t in ts {
      self.push(t);
    }
  }

  pub fn pop(&mut self, count: uint) {
    assert!(count <= self.length);
    self.head = (self.head + count) % self.contents.capacity();
    self.length -= count;
  }

  pub fn is_empty(&self) -> bool {
    self.length == 0
  }

  /// Swap `count` elements from `idx` with the last `count` elements of the
  /// queue, then drop the last `count` elements.
  /// The ordering amongst those `count` elements is maintained.
  pub fn swap_remove(&mut self, idx: uint, count: uint) {
    assert!(count <= self.length);
    self.length -= count;

    assert!(idx <= self.length);

    self.tail = (self.tail + self.contents.capacity() - count) % self.contents.capacity();

    if idx < self.length {
      assert!(
        idx + count <= self.length,
        "Queue::swap_remove in overlapping regions"
      );

      let idx = idx + self.head;

      // At this point, we have a guarantee that the regions do not overlap.
      // Therefore, either the copy-from or copy-to regions might be broken up
      // by the end of the vector, but not both.

      let buffer_wrap_point = self.contents.capacity() - count;
      if idx > buffer_wrap_point {
        assert!(self.contents.len() == self.contents.capacity());

        // copy TO an area of the queue that crosses the end of the buffer.

        let count1 = self.contents.capacity() - idx;
        vec_copy(&mut self.contents, idx, self.tail, count1);
        let count2 = count - count1;
        vec_copy(&mut self.contents, 0, self.tail + count1, count2);
      } else if self.tail > buffer_wrap_point {
        assert!(self.contents.len() == self.contents.capacity());

        // copy FROM an area of the queue that crosses the end of the buffer.

        let count1 = self.contents.capacity() - self.tail;
        vec_copy(&mut self.contents, idx, self.tail, count1);
        let count2 = count - count1;
        vec_copy(&mut self.contents, idx + count1, 0, count2);
      } else {
        vec_copy(&mut self.contents, idx, self.tail, count);
      }
    }
  }

  pub fn len(&self) -> uint {
    self.length
  }

  #[allow(dead_code)]
  pub fn clear(&mut self) {
    self.contents.clear();
    self.head = 0;
    self.tail = 0;
    self.length = 0;
  }

  pub fn iter<'a>(&'a self, low: uint, high: uint) -> QueueItems<'a, T> {
    let (l, h) = self.slices(low, high);
    QueueItems { inner: l.iter().chain(h.iter()) }
  }

  pub fn slices<'a>(&'a self, low: uint, high: uint) -> (&'a [T], &'a [T]) {
    assert!(low <= high);
    assert!(low <= self.length);
    assert!(high <= self.length);
    let (l, h) =
      if low == high {
        (Default::default(), Default::default())
      } else {
        let head = (self.head + low) % self.contents.capacity();
        let tail = (self.head + high) % self.contents.capacity();
        if head < tail {
          (self.contents.slice(head, tail), Default::default())
        } else {
          assert!(self.contents.len() == self.contents.capacity());
          (self.contents.slice(head, self.contents.capacity()), self.contents.slice(0, tail))
        }
      };
    assert!(l.len() + h.len() == high - low);
    (l, h)
  }
}

#[test]
fn push_then_slice() {
  let elems: Vec<int> = Vec::from_slice([1, 2, 3]);
  let mut q = Queue::new(32);
  q.push_all(elems.iter());
  assert!(q.len() == elems.len());
  let (l, h) = q.slices(0, q.len() - 1);
  assert!(l.len() + h.len() == elems.len() - 1);
  for (i, elem) in l.iter().enumerate() {
    assert!(**elem == elems[i]);
  }
  for (i, elem) in h.iter().enumerate() {
    assert!(**elem == elems[i + l.len()]);
  }
}

#[test]
fn push_then_pop() {
  let popped_pushes: Vec<int> = Vec::from_slice([1, 2, 3]);
  let more_pushes: Vec<int> = Vec::from_slice([4, 5]);
  let mut q = Queue::new(32);
  q.push_all(popped_pushes.iter());
  q.push_all(more_pushes.iter());
  assert!(q.len() == popped_pushes.len() + more_pushes.len());
  q.pop(popped_pushes.len());
  assert!(q.len() == more_pushes.len());
  let (l, h) = q.slices(0, q.len());
  assert!(l.len() + h.len() == more_pushes.len());
  for (i, elem) in l.iter().enumerate() {
    assert!(**elem == more_pushes[i]);
  }
  for (i, elem) in h.iter().enumerate() {
    assert!(**elem == more_pushes[i + l.len()]);
  }
}

#[test]
fn wrapped_pushes() {
  static capacity: uint = 32;
  let popped_pushes = Vec::from_elem(capacity / 2, 0i);
  let more_pushes: Vec<int> = range_inclusive(1, capacity as int).collect();
  let mut q: Queue<int> = Queue::new(capacity);
  q.push_all(popped_pushes.iter().map(|&x| x));
  q.pop(popped_pushes.len());
  q.push_all(more_pushes.iter().map(|&x| x));
  assert!(q.len() == more_pushes.len());
  let (l, h) = q.slices(0, q.len());
  assert!(l.len() + h.len() == more_pushes.len());
  assert!(h.len() > 0);
  for (x, y) in l.iter().chain(h.iter()).zip(more_pushes.iter()) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_simple() {
  let mut q: Queue<int> = Queue::new(32);
  q.push_all([1,2,3,4,7,8,5,6i].iter().map(|&x| x));
  q.swap_remove(4, 2);

  let i = q.iter(0, q.len());
  let elems = [1,2,3,4,5,6i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn push_swap_remove_push() {
  let mut q: Queue<int> = Queue::new(32);
  q.push_all([1, 9i].iter().map(|&x| x));
  q.swap_remove(1, 1);
  q.push_all([2, 3, 4, 5i].iter().map(|&x| x));

  let elems = [1, 2, 3, 4, 5i];
  let i = q.iter(0, q.len());
  let mut count = 0;
  for (i, &x) in i.enumerate() {
    assert!(i < elems.len());
    assert_eq!(x, elems[i]);
    count += 1;
  }
  assert!(count == q.len());
  assert!(count == elems.len());
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_end() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [11, 12i];
  let elems = [1,2,3,4,5,6,7,8i];

  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all(elems.iter().map(|&x| x));
  q.swap_remove(4, 4);
  assert!(q.len() == 4);

  let i = q.iter(0, q.len());
  let mut count = 0;
  for (i, &x) in i.enumerate() {
    assert!(i < elems.len());
    assert!(x == elems[i]);
    count += 1;
  }
  assert!(count == q.len());
}

// TODO: clean up this test, de-duplicate, etc.
#[test]
fn swap_remove_to_broken() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [9,9,9,9i];
  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all([1,2,3,7,8,6,4,5i].iter().map(|&x| x));
  q.swap_remove(3, 2);

  let i = q.iter(0, q.len());
  let elems = [1,2,3,4,5,6i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
// TODO: clean up this test, de-duplicate, etc.
fn swap_remove_from_broken() {
  let mut q: Queue<int> = Queue::new(8);
  let popped = [9,9,9,9i];
  q.push_all(popped.iter().map(|&x| x));
  q.pop(popped.len());
  q.push_all([4,5,6,1,2,3i].iter().map(|&x| x));
  q.swap_remove(0, 3);

  let i = q.iter(0, q.len());
  let elems = [1,2,3i];
  let r = elems.iter();
  assert!(i.size_hint() == r.size_hint());
  for (x, y) in i.zip(r) {
    assert!(x == y);
  }
}

#[test]
fn vec_copy_test() {
  let mut v = Vec::from_slice([1,2,3,4,5i]);
  vec_copy(&mut v, 1, 3, 2);
  assert_eq!(v, Vec::from_slice([1, 4, 5, 4, 5i]));
}

pub struct QueueItems<'a, T> { inner: Chain<slice::Items<'a, T>, slice::Items<'a, T>> }

impl<'a, T> Iterator<&'a T> for QueueItems<'a, T> {
  fn next(&mut self) -> Option<&'a T> { self.inner.next() }
  fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn word_count(phrase: &str) -> HashMap<String, u32> {
    let phrase = phrase.to_lowercase();
    let words = phrase.split(|c: char| !c.is_alphanumeric())
        .filter(|s| !s.is_empty())
        .map(|w| w.to_string())
        .collect::<Vec<_>>();

    let mut word_counts = HashMap::new();

    for word in &words {
        if word_counts.contains_key(word) {
            continue;
        }

        let count = words.iter().filter(|&w| { w == word }).count() as u32;

        word_counts.insert(word.clone(), count);
    }

    word_counts
}
<commit_msg>Improve solution for Word Count<commit_after>use std::collections::HashMap;

pub fn word_count(phrase: &str) -> HashMap<String, u32> {
    phrase.to_lowercase()
        .split(|c: char| !c.is_alphanumeric())
        .filter(|s| !s.is_empty())
        .map(|w| w.to_string())
        .fold(HashMap::new(), |mut acc, w| {
            *acc.entry(w).or_insert(0) += 1;
            acc
        })
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;

pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
}

fn make_reserved(v: &Vec<&str>) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "style=\"color: blue;\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
    };
}

pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" => FormatAs::FormatCLike(&*PYTHON_SPEC),

        "html" | "htm" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<commit_msg>More file types<commit_after>use std::collections::HashMap;
use std::path::Path;

pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
}

fn make_reserved(v: &Vec<&str>) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "style=\"color: blue;\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
    };
}

pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" | "mm" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" => FormatAs::FormatCLike(&*PYTHON_SPEC),

        "html" | "htm" | "xhtml" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate reqwest;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::{Read, Write};

use cargo::core::{Dependency, Registry, Source, SourceId, Summary};
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// A single crate from crates.io
#[derive(Debug, Deserialize)]
struct OneCrate {
    #[serde(rename="crate")]
    krate: Crate,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
    #[serde(rename="max_version")]
    version: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: Package,
    dependencies: BTreeMap<String, String>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
struct CrateInformation {
    name: String,
    version: String,
    id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Deserialize)]
struct Modifications {
    #[serde(default)]
    blacklist: Vec<String>,
    #[serde(default)]
    additions: BTreeSet<String>,
}

impl Modifications {
    fn blacklisted(&self, name: &str) -> bool {
        self.blacklist.iter().any(|n| n == name)
    }

    fn additions(&self, existing_names: &[&str]) -> Vec<&str> {
        let existing_names: BTreeSet<_> = existing_names.iter().collect();
        self.additions.iter()
            .map(|n| n.as_str())
            .filter(|n| !existing_names.contains(n))
            .collect()
    }
}

lazy_static! {
    static ref MODIFICATIONS: Modifications = {
        let mut f = File::open("crate-modifications.toml")
            .expect("unable to open crate modifications file");

        let mut d = Vec::new();
        f.read_to_end(&mut d)
            .expect("unable to read crate modifications file");

        toml::from_slice(&d)
            .expect("unable to parse crate modifications file")
    };
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp =
            reqwest::get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(resp.status().is_success());

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self) {
        let added_crates: Vec<_> = {
            let names = self.names();
            let new_names = MODIFICATIONS.additions(&names);

            new_names.into_iter().map(|name| {
                let api_url = format!("https://crates.io/api/v1/crates/{}", name);

                let resp =
                    reqwest::get(&api_url)
                    .unwrap_or_else(|e| panic!("Could not fetch crate {}: {}", name, e));
                assert!(resp.status().is_success());

                let one: OneCrate = serde_json::from_reader(resp)
                    .unwrap_or_else(|e| panic!("Crate {} had invalid JSON: {}", name, e));

                one.krate
            }).collect()
        };

        self.crates.extend(added_crates);
    }

    fn names(&self) -> Vec<&str> {
        self.crates.iter().map(|c| c.name.as_str()).collect()
    }
}

fn decide_features(summary: &Summary) -> Method<'static> {
    lazy_static! {
        static ref PLAYGROUND_FEATURES: Vec<String> = vec!["playground".to_owned()];
    }

    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        Method::Required {
            dev_deps: false,
            features: &*PLAYGROUND_FEATURES,
            uses_default_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, String> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        if MODIFICATIONS.blacklisted(pkg.name()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (name.to_string(), version.to_string()))
         .collect()
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut registry = RegistrySource::remote(&crates_io, &config);
    registry.update().expect("Unable to update registry");

    let mut top = TopCrates::download();
    top.add_curated_crates();

    let mut summaries = Vec::new();
    for Crate { ref name, ref version } in top.crates {
        if MODIFICATIONS.blacklisted(name) {
            continue;
        }

        // Query the registry for summary of this crate.
        let dep = Dependency::parse_no_deprecated(name, Some(version), &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}:{}: {}", name, version, e));

        let matches = registry.query_vec(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}:{}: {}", name, version, e);
        });
        if matches.len() != 1 {
            panic!("expected one registry match for `{}:{}`", name, version);
        }
        let summary = matches.into_iter().next().unwrap();

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let res = resolver::resolve(&summaries, &[], &mut registry, None, true)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let unique_latest_crates = unique_latest_crates(res);
    let manifest = TomlManifest {
        package: Package {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        dependencies: unique_latest_crates.clone(),
    };

    // Write manifest file.
    let cargo_toml = "result.Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);

    let mut infos = Vec::new();

    for (name, version) in unique_latest_crates {
        let pkgid = cargo::core::PackageId::new(&name, &version, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to build PackageId for {} {}: {}", name, version, e));

        let pkg = registry.download(&pkgid)
            .unwrap_or_else(|e| panic!("Unable to download {} {}: {}", name, version, e));

        for target in pkg.targets() {
            if let cargo::core::TargetKind::Lib(_) = *target.kind() {
                infos.push(CrateInformation {
                    name: name.clone(),
                    version: version.clone(),
                    id: target.crate_name()
                })
            }
        }
    }

    let path = "crate-information.json";
    let mut f = File::create(path)
        .unwrap_or_else(|e| panic!("Unable to create {}: {}", path, e));
    serde_json::to_writer_pretty(&mut f, &infos)
        .unwrap_or_else(|e| panic!("Unable to write {}: {}", path, e));
    println!("Wrote {}", path);
}
<commit_msg>Specify codegen-units = 1 in Cargo.toml<commit_after>extern crate cargo;
extern crate reqwest;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::{Read, Write};

use cargo::core::{Dependency, Registry, Source, SourceId, Summary};
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// A single crate from crates.io
#[derive(Debug, Deserialize)]
struct OneCrate {
    #[serde(rename="crate")]
    krate: Crate,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
    #[serde(rename="max_version")]
    version: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: Package,
    profile: Profiles,
    dependencies: BTreeMap<String, String>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
struct CrateInformation {
    name: String,
    version: String,
    id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Deserialize)]
struct Modifications {
    #[serde(default)]
    blacklist: Vec<String>,
    #[serde(default)]
    additions: BTreeSet<String>,
}

/// A profile section in a Cargo.toml file
#[derive(Serialize)]
#[serde(rename_all="kebab-case")]
struct Profile {
    codegen_units: u32,
}

/// Available profile types
#[derive(Serialize)]
struct Profiles {
    dev: Profile,
    release: Profile,
}

impl Modifications {
    fn blacklisted(&self, name: &str) -> bool {
        self.blacklist.iter().any(|n| n == name)
    }

    fn additions(&self, existing_names: &[&str]) -> Vec<&str> {
        let existing_names: BTreeSet<_> = existing_names.iter().collect();
        self.additions.iter()
            .map(|n| n.as_str())
            .filter(|n| !existing_names.contains(n))
            .collect()
    }
}

lazy_static! {
    static ref MODIFICATIONS: Modifications = {
        let mut f = File::open("crate-modifications.toml")
            .expect("unable to open crate modifications file");

        let mut d = Vec::new();
        f.read_to_end(&mut d)
            .expect("unable to read crate modifications file");

        toml::from_slice(&d)
            .expect("unable to parse crate modifications file")
    };
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp =
            reqwest::get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(resp.status().is_success());

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self) {
        let added_crates: Vec<_> = {
            let names = self.names();
            let new_names = MODIFICATIONS.additions(&names);

            new_names.into_iter().map(|name| {
                let api_url = format!("https://crates.io/api/v1/crates/{}", name);

                let resp =
                    reqwest::get(&api_url)
                    .unwrap_or_else(|e| panic!("Could not fetch crate {}: {}", name, e));
                assert!(resp.status().is_success());

                let one: OneCrate = serde_json::from_reader(resp)
                    .unwrap_or_else(|e| panic!("Crate {} had invalid JSON: {}", name, e));

                one.krate
            }).collect()
        };

        self.crates.extend(added_crates);
    }

    fn names(&self) -> Vec<&str> {
        self.crates.iter().map(|c| c.name.as_str()).collect()
    }
}

fn decide_features(summary: &Summary) -> Method<'static> {
    lazy_static! {
        static ref PLAYGROUND_FEATURES: Vec<String> = vec!["playground".to_owned()];
    }

    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        Method::Required {
            dev_deps: false,
            features: &*PLAYGROUND_FEATURES,
            uses_default_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, String> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        if MODIFICATIONS.blacklisted(pkg.name()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (name.to_string(), version.to_string()))
         .collect()
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut registry = RegistrySource::remote(&crates_io, &config);
    registry.update().expect("Unable to update registry");

    let mut top = TopCrates::download();
    top.add_curated_crates();

    let mut summaries = Vec::new();
    for Crate { ref name, ref version } in top.crates {
        if MODIFICATIONS.blacklisted(name) {
            continue;
        }

        // Query the registry for summary of this crate.
        let dep = Dependency::parse_no_deprecated(name, Some(version), &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}:{}: {}", name, version, e));

        let matches = registry.query_vec(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}:{}: {}", name, version, e);
        });
        if matches.len() != 1 {
            panic!("expected one registry match for `{}:{}`", name, version);
        }
        let summary = matches.into_iter().next().unwrap();

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let res = resolver::resolve(&summaries, &[], &mut registry, None, true)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let unique_latest_crates = unique_latest_crates(res);
    let manifest = TomlManifest {
        package: Package {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        profile: Profiles {
            dev: Profile { codegen_units: 1 },
            release: Profile { codegen_units: 1 },
        },
        dependencies: unique_latest_crates.clone(),
    };

    // Write manifest file.
    let cargo_toml = "result.Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);

    let mut infos = Vec::new();

    for (name, version) in unique_latest_crates {
        let pkgid = cargo::core::PackageId::new(&name, &version, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to build PackageId for {} {}: {}", name, version, e));

        let pkg = registry.download(&pkgid)
            .unwrap_or_else(|e| panic!("Unable to download {} {}: {}", name, version, e));

        for target in pkg.targets() {
            if let cargo::core::TargetKind::Lib(_) = *target.kind() {
                infos.push(CrateInformation {
                    name: name.clone(),
                    version: version.clone(),
                    id: target.crate_name()
                })
            }
        }
    }

    let path = "crate-information.json";
    let mut f = File::create(path)
        .unwrap_or_else(|e| panic!("Unable to create {}: {}", path, e));
    serde_json::to_writer_pretty(&mut f, &infos)
        .unwrap_or_else(|e| panic!("Unable to write {}: {}", path, e));
    println!("Wrote {}", path);
}
<|endoftext|>