<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 app_units::Au;
use core_graphics::base::{kCGImageAlphaNoneSkipFirst, kCGImageAlphaPremultipliedLast};
use core_graphics::base::kCGBitmapByteOrder32Little;
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::{CGContext, CGTextDrawingMode};
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::{CGFont, CGGlyph};
use core_graphics::geometry::{CGPoint, CGSize, CGRect};
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use webrender_traits::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
use webrender_traits::{GlyphKey, GlyphOptions, SubpixelPoint};
use gamma_lut::{GammaLut, Color as ColorLut};

pub struct FontContext {
    cg_fonts: HashMap<FontKey, CGFont>,
    ct_fonts: HashMap<(FontKey, Au), CTFont>,
    gamma_lut: GammaLut,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

impl RasterizedGlyph {
    pub fn blank() -> RasterizedGlyph {
        RasterizedGlyph {
            width: 0,
            height: 0,
            bytes: vec![],
        }
    }
}

struct GlyphMetrics {
    rasterized_left: i32,
    rasterized_descent: i32,
    rasterized_ascent: i32,
    rasterized_width: u32,
    rasterized_height: u32,
}

// According to the Skia source code, there's no public API to
// determine if subpixel AA is supported. So jrmuizel ported
// this function from Skia which is used to check if a glyph
// can be rendered with subpixel AA.
fn supports_subpixel_aa() -> bool {
    let mut cg_context = CGContext::create_bitmap_context(1, 1, 8, 4,
                                                          &CGColorSpace::create_device_rgb(),
                                                          kCGImageAlphaNoneSkipFirst |
                                                          kCGBitmapByteOrder32Little);
    let ct_font = core_text::font::new_from_name("Helvetica", 16.).unwrap();
    cg_context.set_should_smooth_fonts(true);
    cg_context.set_should_antialias(true);
    cg_context.set_allows_font_smoothing(true);
    cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
    let point = CGPoint {x: -1., y: 0.};
    let glyph = '|' as CGGlyph;
    ct_font.draw_glyphs(&[glyph], &[point], cg_context.clone());
    let data = cg_context.data();
    data[0] != data[1] || data[1] != data[2]
}

fn get_glyph_metrics(ct_font: &CTFont,
                     glyph: CGGlyph,
                     subpixel_point: &SubpixelPoint) -> GlyphMetrics {
    let bounds = ct_font.get_bounding_rects_for_glyphs(kCTFontDefaultOrientation, &[glyph]);

    let (x_offset, y_offset) = subpixel_point.to_f64();

    // First round out to pixel boundaries
    // CG Origin is bottom left
    let mut left = bounds.origin.x.floor() as i32;
    let mut bottom = bounds.origin.y.floor() as i32;
    let mut right = (bounds.origin.x
                    + bounds.size.width
                    + x_offset).ceil() as i32;
    let mut top = (bounds.origin.y
                  + bounds.size.height
                  + y_offset).ceil() as i32;

    // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
    // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
    // is not currently known, as CG dilates the outlines by some percentage.
    // This is taken from Skia.
    left -= 1;
    bottom -= 1;
    right += 1;
    top += 1;

    let width = right - left;
    let height = top - bottom;

    let metrics = GlyphMetrics {
        rasterized_left: left,
        rasterized_width: width as u32,
        rasterized_height: height as u32,
        rasterized_ascent: top,
        rasterized_descent: -bottom,
    };

    metrics
}

impl FontContext {
    pub fn new() -> FontContext {
        debug!("Test for subpixel AA support: {}", supports_subpixel_aa());

        // Force CG to use sRGB color space to gamma correct.
        let contrast = 0.0;
        let gamma = 0.0;

        FontContext {
            cg_fonts: HashMap::new(),
            ct_fonts: HashMap::new(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8]) {
        if self.cg_fonts.contains_key(font_key) {
            return
        }

        let data_provider = CGDataProvider::from_buffer(bytes);
        let cg_font = match CGFont::from_data_provider(data_provider) {
            Err(_) => return,
            Ok(cg_font) => cg_font,
        };
        self.cg_fonts.insert((*font_key).clone(), cg_font);
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: CGFont) {
        if self.cg_fonts.contains_key(font_key) {
            return
        }

        self.cg_fonts.insert((*font_key).clone(), native_font_handle);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        if let Some(cg_font) = self.cg_fonts.remove(font_key) {
            let ct_font_keys = self.ct_fonts.keys()
                                            .filter(|k| k.0 == *font_key)
                                            .cloned()
                                            .collect::<Vec<_>>();
            for ct_font_key in ct_font_keys {
                self.ct_fonts.remove(&ct_font_key);
            }
        }
    }

    fn get_ct_font(&mut self,
                   font_key: FontKey,
                   size: Au) -> Option<CTFont> {
        match self.ct_fonts.entry(((font_key).clone(), size)) {
            Entry::Occupied(entry) => Some((*entry.get()).clone()),
            Entry::Vacant(entry) => {
                let cg_font = match self.cg_fonts.get(&font_key) {
                    None => return None,
                    Some(cg_font) => cg_font,
                };
                let ct_font = core_text::font::new_from_CGFont(
                        cg_font,
                        size.to_f64_px());
                entry.insert(ct_font.clone());
                Some(ct_font)
            }
        }
    }

    pub fn get_glyph_dimensions(&mut self,
                                key: &GlyphKey) -> Option<GlyphDimensions> {
        self.get_ct_font(key.font_key, key.size).and_then(|ref ct_font| {
            let glyph = key.index as CGGlyph;
            let metrics = get_glyph_metrics(ct_font, glyph, &key.subpixel_point);
            if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
                None
            } else {
                Some(GlyphDimensions {
                    left: metrics.rasterized_left,
                    top: metrics.rasterized_ascent,
                    width: metrics.rasterized_width as u32,
                    height: metrics.rasterized_height as u32,
                })
            }
        })
    }

    // Assumes the pixels here are linear values from CG
    fn gamma_correct_pixels(&self, pixels: &mut Vec<u8>, width: usize,
                            height: usize, render_mode: FontRenderMode,
                            color: ColorU) {
        // Then convert back to gamma corrected values.
        let color_lut = ColorLut::new(color.r,
                                     color.g,
                                     color.b,
                                     color.a);
        match render_mode {
            FontRenderMode::Alpha => {
                self.gamma_lut.preblend_grayscale_bgra(pixels, width,
                                                       height, color_lut);
            },
            FontRenderMode::Subpixel => {
                self.gamma_lut.preblend_bgra(pixels, width, height, color_lut);
            },
            _ => {} // Again, give mono untouched since only the alpha matters.
        }
    }

    #[allow(dead_code)]
    fn print_glyph_data(&mut self, data: &Vec<u8>, width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        println!("Width is: {:?} height: {:?}", width, height);
        for i in 0..height {
            let current_height = i * width * 4;

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

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {
        match self.get_ct_font(key.font_key, key.size) {
            Some(ref ct_font) => {
                let glyph = key.index as CGGlyph;
                let metrics = get_glyph_metrics(ct_font, glyph, &key.subpixel_point);
                if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
                    return Some(RasterizedGlyph::blank())
                }

                let context_flags = match render_mode {
                    FontRenderMode::Subpixel => kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
                    FontRenderMode::Alpha | FontRenderMode::Mono => kCGImageAlphaPremultipliedLast,
                };

                let mut cg_context = CGContext::create_bitmap_context(metrics.rasterized_width as usize,
                                                                      metrics.rasterized_height as usize,
                                                                      8,
                                                                      metrics.rasterized_width as usize * 4,
                                                                      &CGColorSpace::create_device_rgb(),
                                                                      context_flags);

                // Tested on mac OS Sierra, 10.12
                // For Mono + alpha, the only values that matter are the alpha values.
                // For subpixel, we need each individual rgb channel.
                // CG has two individual glyphs for subpixel AA (pre-10.11, this is not true):
                // 1) black text on white opaque background
                // 2) white text on black opaque background
                // Gecko does (1). Note, the BG must be opaque for subpixel AA to work.
                // See https://bugzilla.mozilla.org/show_bug.cgi?id=1230366#c35
                //
                // For grayscale / mono, CG still produces two glyphs, but it doesn't matter
                // 1) black text on transparent white - only alpha values filled
                // 2) white text on transparent black - channels == alpha
                //
                // If we draw grayscale/mono on an opaque background
                // the RGB channels are the alpha values from transparent backgrounds
                // with the alpha set as opaque.
                // At the end of all this, WR expects individual RGB channels and ignores alpha
                // for subpixel AA.
                // For alpha/mono, WR ignores all channels other than alpha.
                // Also note that WR expects text to be black bg with white text, so invert
                // when we draw the glyphs.
                let (antialias, smooth) = match render_mode {
                    FontRenderMode::Subpixel => (true, true),
                    FontRenderMode::Alpha => (true, false),
                    FontRenderMode::Mono => (false, false),
                };

                // These are always true in Gecko, even for non-AA fonts
                cg_context.set_allows_font_subpixel_positioning(true);
                cg_context.set_should_subpixel_position_fonts(true);

                // Don't quantize because we're doing it already.
                cg_context.set_allows_font_subpixel_quantization(false);
                cg_context.set_should_subpixel_quantize_fonts(false);

                cg_context.set_allows_font_smoothing(smooth);
                cg_context.set_should_smooth_fonts(smooth);
                cg_context.set_allows_antialiasing(antialias);
                cg_context.set_should_antialias(antialias);

                let (x_offset, y_offset) = key.subpixel_point.to_f64();

                // CG Origin is bottom left, WR is top left. Need -y offset
                let rasterization_origin = CGPoint {
                    x: -metrics.rasterized_left as f64 + x_offset,
                    y: metrics.rasterized_descent as f64 - y_offset,
                };

                // Always draw black text on a white background
                // Fill the background
                cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
                let rect = CGRect {
                    origin: CGPoint {
                        x: 0.0,
                        y: 0.0,
                    },
                    size: CGSize {
                        width: metrics.rasterized_width as f64,
                        height: metrics.rasterized_height as f64,
                    }
                };
                cg_context.fill_rect(rect);

                // Set the text color
                cg_context.set_rgb_fill_color(0.0, 0.0, 0.0, 1.0);
                cg_context.set_text_drawing_mode(CGTextDrawingMode::CGTextFill);
                ct_font.draw_glyphs(&[glyph], &[rasterization_origin], cg_context.clone());

                let mut rasterized_pixels = cg_context.data().to_vec();

                // Convert to linear space for subpixel AA.
                // We explicitly do not do this for grayscale AA
                if render_mode == FontRenderMode::Subpixel {
                    self.gamma_lut.coregraphics_convert_to_linear_bgra(&mut rasterized_pixels,
                                                                       metrics.rasterized_width as usize,
                                                                       metrics.rasterized_height as usize);
                }

                // We need to invert the pixels back since right now
                // transparent pixels are actually opaque white.
                for i in 0..metrics.rasterized_height {
                    let current_height = (i * metrics.rasterized_width * 4) as usize;
                    let end_row = current_height + (metrics.rasterized_width as usize * 4);

                    for mut pixel in rasterized_pixels[current_height .. end_row].chunks_mut(4) {
                        pixel[0] = 255 - pixel[0];
                        pixel[1] = 255 - pixel[1];
                        pixel[2] = 255 - pixel[2];

                        pixel[3] = match render_mode {
                            FontRenderMode::Subpixel => 255,
                            _ => {
                                assert_eq!(pixel[0], pixel[1]);
                                assert_eq!(pixel[0], pixel[2]);
                                pixel[0]
                            }
                        }; // end match
                    } // end row
                } // end height

                self.gamma_correct_pixels(&mut rasterized_pixels,
                                          metrics.rasterized_width as usize,
                                          metrics.rasterized_height as usize,
                                          render_mode,
                                          key.color);

                Some(RasterizedGlyph {
                    width: metrics.rasterized_width,
                    height: metrics.rasterized_height,
                    bytes: rasterized_pixels,
                })
            }
            None => {
                return Some(RasterizedGlyph::blank());
            }
        }
    }
}

<commit_msg>Auto merge of #977 - jrmuizel:drain, r=emilio<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 app_units::Au;
use core_graphics::base::{kCGImageAlphaNoneSkipFirst, kCGImageAlphaPremultipliedLast};
use core_graphics::base::kCGBitmapByteOrder32Little;
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::{CGContext, CGTextDrawingMode};
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::{CGFont, CGGlyph};
use core_graphics::geometry::{CGPoint, CGSize, CGRect};
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use webrender_traits::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
use webrender_traits::{GlyphKey, GlyphOptions, SubpixelPoint};
use gamma_lut::{GammaLut, Color as ColorLut};

pub struct FontContext {
    cg_fonts: HashMap<FontKey, CGFont>,
    ct_fonts: HashMap<(FontKey, Au), CTFont>,
    gamma_lut: GammaLut,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

impl RasterizedGlyph {
    pub fn blank() -> RasterizedGlyph {
        RasterizedGlyph {
            width: 0,
            height: 0,
            bytes: vec![],
        }
    }
}

struct GlyphMetrics {
    rasterized_left: i32,
    rasterized_descent: i32,
    rasterized_ascent: i32,
    rasterized_width: u32,
    rasterized_height: u32,
}

// According to the Skia source code, there's no public API to
// determine if subpixel AA is supported. So jrmuizel ported
// this function from Skia which is used to check if a glyph
// can be rendered with subpixel AA.
fn supports_subpixel_aa() -> bool {
    let mut cg_context = CGContext::create_bitmap_context(1, 1, 8, 4,
                                                          &CGColorSpace::create_device_rgb(),
                                                          kCGImageAlphaNoneSkipFirst |
                                                          kCGBitmapByteOrder32Little);
    let ct_font = core_text::font::new_from_name("Helvetica", 16.).unwrap();
    cg_context.set_should_smooth_fonts(true);
    cg_context.set_should_antialias(true);
    cg_context.set_allows_font_smoothing(true);
    cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
    let point = CGPoint {x: -1., y: 0.};
    let glyph = '|' as CGGlyph;
    ct_font.draw_glyphs(&[glyph], &[point], cg_context.clone());
    let data = cg_context.data();
    data[0] != data[1] || data[1] != data[2]
}

fn get_glyph_metrics(ct_font: &CTFont,
                     glyph: CGGlyph,
                     subpixel_point: &SubpixelPoint) -> GlyphMetrics {
    let bounds = ct_font.get_bounding_rects_for_glyphs(kCTFontDefaultOrientation, &[glyph]);

    let (x_offset, y_offset) = subpixel_point.to_f64();

    // First round out to pixel boundaries
    // CG Origin is bottom left
    let mut left = bounds.origin.x.floor() as i32;
    let mut bottom = bounds.origin.y.floor() as i32;
    let mut right = (bounds.origin.x
                    + bounds.size.width
                    + x_offset).ceil() as i32;
    let mut top = (bounds.origin.y
                  + bounds.size.height
                  + y_offset).ceil() as i32;

    // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
    // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
    // is not currently known, as CG dilates the outlines by some percentage.
    // This is taken from Skia.
    left -= 1;
    bottom -= 1;
    right += 1;
    top += 1;

    let width = right - left;
    let height = top - bottom;

    let metrics = GlyphMetrics {
        rasterized_left: left,
        rasterized_width: width as u32,
        rasterized_height: height as u32,
        rasterized_ascent: top,
        rasterized_descent: -bottom,
    };

    metrics
}

impl FontContext {
    pub fn new() -> FontContext {
        debug!("Test for subpixel AA support: {}", supports_subpixel_aa());

        // Force CG to use sRGB color space to gamma correct.
        let contrast = 0.0;
        let gamma = 0.0;

        FontContext {
            cg_fonts: HashMap::new(),
            ct_fonts: HashMap::new(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8]) {
        if self.cg_fonts.contains_key(font_key) {
            return
        }

        let data_provider = CGDataProvider::from_buffer(bytes);
        let cg_font = match CGFont::from_data_provider(data_provider) {
            Err(_) => return,
            Ok(cg_font) => cg_font,
        };
        self.cg_fonts.insert((*font_key).clone(), cg_font);
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: CGFont) {
        if self.cg_fonts.contains_key(font_key) {
            return
        }

        self.cg_fonts.insert((*font_key).clone(), native_font_handle);
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        if let Some(cg_font) = self.cg_fonts.remove(font_key) {
            // Unstable Rust has a retain() method on HashMap that will
            // let us do this in-place. https://github.com/rust-lang/rust/issues/36648
            let ct_font_keys = self.ct_fonts.keys()
                                            .filter(|k| k.0 == *font_key)
                                            .cloned()
                                            .collect::<Vec<_>>();
            for ct_font_key in ct_font_keys {
                self.ct_fonts.remove(&ct_font_key);
            }
        }
    }

    fn get_ct_font(&mut self,
                   font_key: FontKey,
                   size: Au) -> Option<CTFont> {
        match self.ct_fonts.entry(((font_key).clone(), size)) {
            Entry::Occupied(entry) => Some((*entry.get()).clone()),
            Entry::Vacant(entry) => {
                let cg_font = match self.cg_fonts.get(&font_key) {
                    None => return None,
                    Some(cg_font) => cg_font,
                };
                let ct_font = core_text::font::new_from_CGFont(
                        cg_font,
                        size.to_f64_px());
                entry.insert(ct_font.clone());
                Some(ct_font)
            }
        }
    }

    pub fn get_glyph_dimensions(&mut self,
                                key: &GlyphKey) -> Option<GlyphDimensions> {
        self.get_ct_font(key.font_key, key.size).and_then(|ref ct_font| {
            let glyph = key.index as CGGlyph;
            let metrics = get_glyph_metrics(ct_font, glyph, &key.subpixel_point);
            if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
                None
            } else {
                Some(GlyphDimensions {
                    left: metrics.rasterized_left,
                    top: metrics.rasterized_ascent,
                    width: metrics.rasterized_width as u32,
                    height: metrics.rasterized_height as u32,
                })
            }
        })
    }

    // Assumes the pixels here are linear values from CG
    fn gamma_correct_pixels(&self, pixels: &mut Vec<u8>, width: usize,
                            height: usize, render_mode: FontRenderMode,
                            color: ColorU) {
        // Then convert back to gamma corrected values.
        let color_lut = ColorLut::new(color.r,
                                     color.g,
                                     color.b,
                                     color.a);
        match render_mode {
            FontRenderMode::Alpha => {
                self.gamma_lut.preblend_grayscale_bgra(pixels, width,
                                                       height, color_lut);
            },
            FontRenderMode::Subpixel => {
                self.gamma_lut.preblend_bgra(pixels, width, height, color_lut);
            },
            _ => {} // Again, give mono untouched since only the alpha matters.
        }
    }

    #[allow(dead_code)]
    fn print_glyph_data(&mut self, data: &Vec<u8>, width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        println!("Width is: {:?} height: {:?}", width, height);
        for i in 0..height {
            let current_height = i * width * 4;

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

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {
        match self.get_ct_font(key.font_key, key.size) {
            Some(ref ct_font) => {
                let glyph = key.index as CGGlyph;
                let metrics = get_glyph_metrics(ct_font, glyph, &key.subpixel_point);
                if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
                    return Some(RasterizedGlyph::blank())
                }

                let context_flags = match render_mode {
                    FontRenderMode::Subpixel => kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
                    FontRenderMode::Alpha | FontRenderMode::Mono => kCGImageAlphaPremultipliedLast,
                };

                let mut cg_context = CGContext::create_bitmap_context(metrics.rasterized_width as usize,
                                                                      metrics.rasterized_height as usize,
                                                                      8,
                                                                      metrics.rasterized_width as usize * 4,
                                                                      &CGColorSpace::create_device_rgb(),
                                                                      context_flags);

                // Tested on mac OS Sierra, 10.12
                // For Mono + alpha, the only values that matter are the alpha values.
                // For subpixel, we need each individual rgb channel.
                // CG has two individual glyphs for subpixel AA (pre-10.11, this is not true):
                // 1) black text on white opaque background
                // 2) white text on black opaque background
                // Gecko does (1). Note, the BG must be opaque for subpixel AA to work.
                // See https://bugzilla.mozilla.org/show_bug.cgi?id=1230366#c35
                //
                // For grayscale / mono, CG still produces two glyphs, but it doesn't matter
                // 1) black text on transparent white - only alpha values filled
                // 2) white text on transparent black - channels == alpha
                //
                // If we draw grayscale/mono on an opaque background
                // the RGB channels are the alpha values from transparent backgrounds
                // with the alpha set as opaque.
                // At the end of all this, WR expects individual RGB channels and ignores alpha
                // for subpixel AA.
                // For alpha/mono, WR ignores all channels other than alpha.
                // Also note that WR expects text to be black bg with white text, so invert
                // when we draw the glyphs.
                let (antialias, smooth) = match render_mode {
                    FontRenderMode::Subpixel => (true, true),
                    FontRenderMode::Alpha => (true, false),
                    FontRenderMode::Mono => (false, false),
                };

                // These are always true in Gecko, even for non-AA fonts
                cg_context.set_allows_font_subpixel_positioning(true);
                cg_context.set_should_subpixel_position_fonts(true);

                // Don't quantize because we're doing it already.
                cg_context.set_allows_font_subpixel_quantization(false);
                cg_context.set_should_subpixel_quantize_fonts(false);

                cg_context.set_allows_font_smoothing(smooth);
                cg_context.set_should_smooth_fonts(smooth);
                cg_context.set_allows_antialiasing(antialias);
                cg_context.set_should_antialias(antialias);

                let (x_offset, y_offset) = key.subpixel_point.to_f64();

                // CG Origin is bottom left, WR is top left. Need -y offset
                let rasterization_origin = CGPoint {
                    x: -metrics.rasterized_left as f64 + x_offset,
                    y: metrics.rasterized_descent as f64 - y_offset,
                };

                // Always draw black text on a white background
                // Fill the background
                cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
                let rect = CGRect {
                    origin: CGPoint {
                        x: 0.0,
                        y: 0.0,
                    },
                    size: CGSize {
                        width: metrics.rasterized_width as f64,
                        height: metrics.rasterized_height as f64,
                    }
                };
                cg_context.fill_rect(rect);

                // Set the text color
                cg_context.set_rgb_fill_color(0.0, 0.0, 0.0, 1.0);
                cg_context.set_text_drawing_mode(CGTextDrawingMode::CGTextFill);
                ct_font.draw_glyphs(&[glyph], &[rasterization_origin], cg_context.clone());

                let mut rasterized_pixels = cg_context.data().to_vec();

                // Convert to linear space for subpixel AA.
                // We explicitly do not do this for grayscale AA
                if render_mode == FontRenderMode::Subpixel {
                    self.gamma_lut.coregraphics_convert_to_linear_bgra(&mut rasterized_pixels,
                                                                       metrics.rasterized_width as usize,
                                                                       metrics.rasterized_height as usize);
                }

                // We need to invert the pixels back since right now
                // transparent pixels are actually opaque white.
                for i in 0..metrics.rasterized_height {
                    let current_height = (i * metrics.rasterized_width * 4) as usize;
                    let end_row = current_height + (metrics.rasterized_width as usize * 4);

                    for mut pixel in rasterized_pixels[current_height .. end_row].chunks_mut(4) {
                        pixel[0] = 255 - pixel[0];
                        pixel[1] = 255 - pixel[1];
                        pixel[2] = 255 - pixel[2];

                        pixel[3] = match render_mode {
                            FontRenderMode::Subpixel => 255,
                            _ => {
                                assert_eq!(pixel[0], pixel[1]);
                                assert_eq!(pixel[0], pixel[2]);
                                pixel[0]
                            }
                        }; // end match
                    } // end row
                } // end height

                self.gamma_correct_pixels(&mut rasterized_pixels,
                                          metrics.rasterized_width as usize,
                                          metrics.rasterized_height as usize,
                                          render_mode,
                                          key.color);

                Some(RasterizedGlyph {
                    width: metrics.rasterized_width,
                    height: metrics.rasterized_height,
                    bytes: rasterized_pixels,
                })
            }
            None => {
                return Some(RasterizedGlyph::blank());
            }
        }
    }
}

<|endoftext|>


<commit_before>type point = {x: int, y: int};

impl point_ops for point {
    fn +(other: point) -> point {
        {x: self.x + other.x, y: self.y + other.y}
    }
    fn -(other: point) -> point {
        {x: self.x - other.x, y: self.y - other.y}
    }
    fn unary-() -> point {
        {x: -self.x, y: -self.y}
    }
    fn [](x: bool) -> int {
        if x { self.x } else { self.y }
    }
}

fn main() {
    let p = {x: 10, y: 20};
    p += {x: 101, y: 102};
    p -= {x: 100, y: 100};
    assert p + {x: 5, y: 5} == {x: 16, y: 27};
    assert -p == {x: -11, y: -22};
    assert p[true] == 11;
    assert p[false] == 22;
}
<commit_msg>Add test case for issue #1733<commit_after>type point = {x: int, y: int};

impl point_ops for point {
    fn +(other: point) -> point {
        {x: self.x + other.x, y: self.y + other.y}
    }
    fn -(other: point) -> point {
        {x: self.x - other.x, y: self.y - other.y}
    }
    fn unary-() -> point {
        {x: -self.x, y: -self.y}
    }
    fn [](x: bool) -> int {
        if x { self.x } else { self.y }
    }
}

fn main() {
    let p = {x: 10, y: 20};
    p += {x: 101, y: 102};
    p -= {x: 100, y: 100};
    assert p + {x: 5, y: 5} == {x: 16, y: 27};
    assert -p == {x: -11, y: -22};
    assert p[true] == 11;
    assert p[false] == 22;
    // Issue #1733
    fn~(_x: int){}(p[true]);
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Maciej Dziardziel <fiedzia@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (vars) cvar exitstatus
// spell-checker:ignore (sys/unix) WIFSIGNALED

//! Set of functions to manage IDs

use libc::{gid_t, pid_t, uid_t};
use std::fmt;
use std::io;
use std::process::Child;
use std::process::ExitStatus as StdExitStatus;
use std::thread;
use std::time::{Duration, Instant};

/// `geteuid()` returns the effective user ID of the calling process.
pub fn geteuid() -> uid_t {
    unsafe { libc::geteuid() }
}

/// `getegid()` returns the effective group ID of the calling process.
pub fn getegid() -> gid_t {
    unsafe { libc::getegid() }
}

/// `getgid()` returns the real group ID of the calling process.
pub fn getgid() -> gid_t {
    unsafe { libc::getgid() }
}

/// `getuid()` returns the real user ID of the calling process.
pub fn getuid() -> uid_t {
    unsafe { libc::getuid() }
}

// This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus {
    Code(i32),
    Signal(i32),
}

#[allow(clippy::trivially_copy_pass_by_ref)]
impl ExitStatus {
    fn from_std_status(status: StdExitStatus) -> Self {
        #[cfg(unix)]
        {
            use std::os::unix::process::ExitStatusExt;

            if let Some(signal) = status.signal() {
                return ExitStatus::Signal(signal);
            }
        }

        // NOTE: this should never fail as we check if the program exited through a signal above
        ExitStatus::Code(status.code().unwrap())
    }

    pub fn success(&self) -> bool {
        match *self {
            ExitStatus::Code(code) => code == 0,
            _ => false,
        }
    }

    pub fn code(&self) -> Option<i32> {
        match *self {
            ExitStatus::Code(code) => Some(code),
            _ => None,
        }
    }

    pub fn signal(&self) -> Option<i32> {
        match *self {
            ExitStatus::Signal(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExitStatus::Code(code) => write!(f, "exit code: {}", code),
            ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
        }
    }
}

/// Missing methods for Child objects
pub trait ChildExt {
    /// Send a signal to a Child process.
    fn send_signal(&mut self, signal: usize) -> io::Result<()>;

    /// Wait for a process to finish or return after the specified duration.
    /// A `timeout` of zero disables the timeout.
    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>>;
}

impl ChildExt for Child {
    fn send_signal(&mut self, signal: usize) -> io::Result<()> {
        if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }

    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
        if timeout == Duration::from_micros(0) {
            return self
                .wait()
                .map(|status| Some(ExitStatus::from_std_status(status)));
        }
        // .try_wait() doesn't drop stdin, so we do it manually
        drop(self.stdin.take());

        let start = Instant::now();
        loop {
            if let Some(status) = self.try_wait()? {
                return Ok(Some(ExitStatus::from_std_status(status)));
            }

            if start.elapsed() >= timeout {
                break;
            }

            // XXX: this is kinda gross, but it's cleaner than starting a thread just to wait
            //      (which was the previous solution).  We might want to use a different duration
            //      here as well
            thread::sleep(Duration::from_millis(100));
        }

        Ok(None)
    }
}
<commit_msg>uucore::process: Add a few notes<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Maciej Dziardziel <fiedzia@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (vars) cvar exitstatus
// spell-checker:ignore (sys/unix) WIFSIGNALED

//! Set of functions to manage IDs

use libc::{gid_t, pid_t, uid_t};
use std::fmt;
use std::io;
use std::process::Child;
use std::process::ExitStatus as StdExitStatus;
use std::thread;
use std::time::{Duration, Instant};

// SAFETY: These functions always succeed and return simple integers.

/// `geteuid()` returns the effective user ID of the calling process.
pub fn geteuid() -> uid_t {
    unsafe { libc::geteuid() }
}

/// `getegid()` returns the effective group ID of the calling process.
pub fn getegid() -> gid_t {
    unsafe { libc::getegid() }
}

/// `getgid()` returns the real group ID of the calling process.
pub fn getgid() -> gid_t {
    unsafe { libc::getgid() }
}

/// `getuid()` returns the real user ID of the calling process.
pub fn getuid() -> uid_t {
    unsafe { libc::getuid() }
}

// This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus {
    Code(i32),
    Signal(i32),
}

#[allow(clippy::trivially_copy_pass_by_ref)]
impl ExitStatus {
    fn from_std_status(status: StdExitStatus) -> Self {
        #[cfg(unix)]
        {
            use std::os::unix::process::ExitStatusExt;

            if let Some(signal) = status.signal() {
                return ExitStatus::Signal(signal);
            }
        }

        // NOTE: this should never fail as we check if the program exited through a signal above
        ExitStatus::Code(status.code().unwrap())
    }

    pub fn success(&self) -> bool {
        match *self {
            ExitStatus::Code(code) => code == 0,
            _ => false,
        }
    }

    pub fn code(&self) -> Option<i32> {
        match *self {
            ExitStatus::Code(code) => Some(code),
            _ => None,
        }
    }

    pub fn signal(&self) -> Option<i32> {
        match *self {
            ExitStatus::Signal(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExitStatus::Code(code) => write!(f, "exit code: {}", code),
            ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
        }
    }
}

/// Missing methods for Child objects
pub trait ChildExt {
    /// Send a signal to a Child process.
    ///
    /// Caller beware: if the process already exited then you may accidentally
    /// send the signal to an unrelated process that recycled the PID.
    fn send_signal(&mut self, signal: usize) -> io::Result<()>;

    /// Wait for a process to finish or return after the specified duration.
    /// A `timeout` of zero disables the timeout.
    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>>;
}

impl ChildExt for Child {
    fn send_signal(&mut self, signal: usize) -> io::Result<()> {
        if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }

    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
        if timeout == Duration::from_micros(0) {
            return self
                .wait()
                .map(|status| Some(ExitStatus::from_std_status(status)));
        }
        // .try_wait() doesn't drop stdin, so we do it manually
        drop(self.stdin.take());

        let start = Instant::now();
        loop {
            if let Some(status) = self.try_wait()? {
                return Ok(Some(ExitStatus::from_std_status(status)));
            }

            if start.elapsed() >= timeout {
                break;
            }

            // XXX: this is kinda gross, but it's cleaner than starting a thread just to wait
            //      (which was the previous solution).  We might want to use a different duration
            //      here as well
            thread::sleep(Duration::from_millis(100));
        }

        Ok(None)
    }
}
<|endoftext|>


<commit_before>use super::{safe, try_into_option, Environment, DiagnosticRecord, GetDiagRec, Result, Version3};
use ffi;
use std::collections::HashMap;
use std::cmp::max;

/// Holds name and description of a datasource
///
/// Can be obtained via `Environment::data_sources`
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DataSourceInfo {
    /// Name of the data source
    pub server_name: String,
    /// Description of the data source
    pub driver: String,
}

/// Struct holding information available on a driver.
///
/// Can be obtained via `Environment::drivers`
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DriverInfo {
    /// Name of the odbc driver
    pub description: String,
    /// List of attributes of the odbc driver
    pub attributes: HashMap<String, String>,
}

type SqlInfoMethod = fn(&mut safe::Environment<safe::Odbc3>,
                        ffi::FetchOrientation,
                        &mut [u8],
                        &mut [u8])
                        -> safe::ReturnOption<(i16, i16)>;

impl Environment<Version3> {
    /// Called by drivers to pares list of attributes
    ///
    /// Key value pairs are seperated by `\0`. Key and value are seperated by `=`
    fn parse_attributes(attributes: &str) -> HashMap<String, String> {
        attributes
            .split('\0')
            .take_while(|kv_str| *kv_str != String::new())
            .map(|kv_str| {
                let mut iter = kv_str.split('=');
                let key = iter.next().unwrap();
                let value = iter.next().unwrap();
                (key.to_string(), value.to_string())
            })
            .collect()
    }

    /// Stores all driver description and attributes in a Vec
    pub fn drivers(&mut self) -> Result<Vec<DriverInfo>> {
        // Iterate twice, once for reading the maximum required buffer lengths so we can read
        // everything without truncating and a second time for actually storing the values
        // alloc_info iterates ones over every driver to obtain the requiered buffer sizes
        let (max_desc, max_attr, num_drivers) = self.alloc_info(
            safe::Environment::drivers,
            ffi::SQL_FETCH_FIRST,
        )?;

        let mut driver_list = Vec::with_capacity(num_drivers);

        if num_drivers > 0 {
            let mut description_buffer = vec![0; (max_desc + 1) as usize];
            let mut attribute_buffer = vec![0; (max_attr + 1) as usize];
            while let Some((desc, attr)) =
            self.get_info(
                safe::Environment::drivers,
                ffi::SQL_FETCH_NEXT,
                &mut description_buffer,
                &mut attribute_buffer,
            )?
                {
                    driver_list.push(DriverInfo {
                        description: desc.into_owned(),
                        attributes: Self::parse_attributes(&attr),
                    })
                }
        }

        Ok(driver_list)
    }

    /// Stores all data source server names and descriptions in a Vec
    pub fn data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST)
    }

    /// Stores all sytem data source server names and descriptions in a Vec
    pub fn system_data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST_SYSTEM)
    }

    /// Stores all user data source server names and descriptions in a Vec
    pub fn user_data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST_USER)
    }

    /// Use SQL_FETCH_FIRST, SQL_FETCH_FIRST_USER or SQL_FETCH_FIRST_SYSTEM, to get all, user or
    /// system data sources
    fn data_sources_impl(
        &mut self,
        direction: ffi::FetchOrientation,
    ) -> Result<Vec<DataSourceInfo>> {

        // alloc_info iterates ones over every datasource to obtain the requiered buffer sizes
        let (max_name, max_desc, num_sources) =
            self.alloc_info(safe::Environment::data_sources, direction)?;

        let mut source_list = Vec::with_capacity(num_sources);

        if num_sources > 0 {
            let mut name_buffer: Vec<_> = (0..(max_name + 1)).map(|_| 0u8).collect();
            let mut description_buffer: Vec<_> = (0..(max_desc + 1)).map(|_| 0u8).collect();

            // Before we call SQLDataSources with SQL_FETCH_NEXT, we have to call it with either
            // SQL_FETCH_FIRST, SQL_FETCH_FIRST_USER or SQL_FETCH_FIRST_SYSTEM, to get all, user or
            // system data sources
            if let Some((name, desc)) =
            self.get_info(
                safe::Environment::data_sources,
                direction,
                &mut name_buffer,
                &mut description_buffer,
            )?
                {
                    source_list.push(DataSourceInfo {
                        server_name: name.into_owned(),
                        driver: desc.into_owned(),
                })
            } else {
                return Ok(source_list);
            }

            while let Some((name, desc)) =
            self.get_info(
                safe::Environment::data_sources,
                ffi::SQL_FETCH_NEXT,
                &mut name_buffer,
                &mut description_buffer,
            )?
                {
                    source_list.push(DataSourceInfo {
                        server_name: name.into_owned(),
                        driver: desc.into_owned(),
                    })
                }
        }

        Ok(source_list)
    }

    /// Calls either SQLDrivers or SQLDataSources with the two given buffers and parses the result
    /// into a `(&str,&str)`
    fn get_info<'a, 'b>(
        &mut self,
        f: SqlInfoMethod,
        direction: ffi::FetchOrientation,
        buf1: &'a mut [u8],
        buf2: &'b mut [u8],
    ) -> Result<Option<(::std::borrow::Cow<'a, str>, ::std::borrow::Cow<'b, str>)>> {
        let result = f(&mut self.safe, direction, buf1, buf2);
        match try_into_option(result, self)? {
            Some((len1, len2)) => unsafe {
                Ok(Some((
                    ::environment::DB_ENCODING.decode(&buf1[0..(len1 as usize)]).0,
                    ::environment::DB_ENCODING.decode(&buf2[0..(len2 as usize)]).0,
                )))
            }
            None => Ok(None),
        }
    }

    /// Finds the maximum size required for description buffers
    fn alloc_info(
        &mut self,
        f: SqlInfoMethod,
        direction: ffi::FetchOrientation,
    ) -> Result<(ffi::SQLSMALLINT, ffi::SQLSMALLINT, usize)> {
        let mut string_buf1 = [0; 0];
        let mut string_buf2 = [0; 0];
        let mut max1 = 0;
        let mut max2 = 0;
        let mut count = 0;

        let mut result = f(
            &mut self.safe,
            direction,
            &mut string_buf1,
            &mut string_buf2,
        );

        loop {

            match result {
                safe::ReturnOption::Success((buf1_length_out, buf2_length_out)) |
                safe::ReturnOption::Info((buf1_length_out, buf2_length_out)) => {
                    count += 1;
                    max1 = max(max1, buf1_length_out);
                    max2 = max(max2, buf2_length_out);
                }
                safe::ReturnOption::NoData(()) => break,
                safe::ReturnOption::Error(()) => {
                    let diag = self.get_diag_rec(1).unwrap_or_else(DiagnosticRecord::empty);
                    error!("{}", diag);
                    return Err(diag);
                }
            }

            result = f(
                &mut self.safe,
                ffi::SQL_FETCH_NEXT,
                &mut string_buf1,
                &mut string_buf2,
            )
        }

        Ok((max1, max2, count))
    }
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn parse_attributes() {
        let buffer = "APILevel=2\0ConnectFunctions=YYY\0CPTimeout=60\0DriverODBCVer=03.\
                      50\0FileUsage=0\0SQLLevel=1\0UsageCount=1\0\0";
        let attributes = Environment::parse_attributes(buffer);
        assert_eq!(attributes["APILevel"], "2");
        assert_eq!(attributes["ConnectFunctions"], "YYY");
        assert_eq!(attributes["CPTimeout"], "60");
        assert_eq!(attributes["DriverODBCVer"], "03.50");
        assert_eq!(attributes["FileUsage"], "0");
        assert_eq!(attributes["SQLLevel"], "1");
        assert_eq!(attributes["UsageCount"], "1");
    }
}
<commit_msg>Fix list_drivers by a non-zero length buffer<commit_after>use super::{safe, try_into_option, Environment, DiagnosticRecord, GetDiagRec, Result, Version3};
use ffi;
use std::collections::HashMap;
use std::cmp::max;

/// Holds name and description of a datasource
///
/// Can be obtained via `Environment::data_sources`
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DataSourceInfo {
    /// Name of the data source
    pub server_name: String,
    /// Description of the data source
    pub driver: String,
}

/// Struct holding information available on a driver.
///
/// Can be obtained via `Environment::drivers`
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DriverInfo {
    /// Name of the odbc driver
    pub description: String,
    /// List of attributes of the odbc driver
    pub attributes: HashMap<String, String>,
}

type SqlInfoMethod = fn(&mut safe::Environment<safe::Odbc3>,
                        ffi::FetchOrientation,
                        &mut [u8],
                        &mut [u8])
                        -> safe::ReturnOption<(i16, i16)>;

impl Environment<Version3> {
    /// Called by drivers to pares list of attributes
    ///
    /// Key value pairs are seperated by `\0`. Key and value are seperated by `=`
    fn parse_attributes(attributes: &str) -> HashMap<String, String> {
        attributes
            .split('\0')
            .take_while(|kv_str| *kv_str != String::new())
            .map(|kv_str| {
                let mut iter = kv_str.split('=');
                let key = iter.next().unwrap();
                let value = iter.next().unwrap();
                (key.to_string(), value.to_string())
            })
            .collect()
    }

    /// Stores all driver description and attributes in a Vec
    pub fn drivers(&mut self) -> Result<Vec<DriverInfo>> {
        // Iterate twice, once for reading the maximum required buffer lengths so we can read
        // everything without truncating and a second time for actually storing the values
        // alloc_info iterates ones over every driver to obtain the requiered buffer sizes
        let (max_desc, max_attr, num_drivers) = self.alloc_info(
            safe::Environment::drivers,
            ffi::SQL_FETCH_FIRST,
        )?;

        let mut driver_list = Vec::with_capacity(num_drivers);

        if num_drivers > 0 {
            let mut description_buffer = vec![0; (max_desc + 1) as usize];
            let mut attribute_buffer = vec![0; (max_attr + 1) as usize];
            while let Some((desc, attr)) =
            self.get_info(
                safe::Environment::drivers,
                ffi::SQL_FETCH_NEXT,
                &mut description_buffer,
                &mut attribute_buffer,
            )?
                {
                    driver_list.push(DriverInfo {
                        description: desc.into_owned(),
                        attributes: Self::parse_attributes(&attr),
                    })
                }
        }

        Ok(driver_list)
    }

    /// Stores all data source server names and descriptions in a Vec
    pub fn data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST)
    }

    /// Stores all sytem data source server names and descriptions in a Vec
    pub fn system_data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST_SYSTEM)
    }

    /// Stores all user data source server names and descriptions in a Vec
    pub fn user_data_sources(&mut self) -> Result<Vec<DataSourceInfo>> {
        self.data_sources_impl(ffi::SQL_FETCH_FIRST_USER)
    }

    /// Use SQL_FETCH_FIRST, SQL_FETCH_FIRST_USER or SQL_FETCH_FIRST_SYSTEM, to get all, user or
    /// system data sources
    fn data_sources_impl(
        &mut self,
        direction: ffi::FetchOrientation,
    ) -> Result<Vec<DataSourceInfo>> {

        // alloc_info iterates ones over every datasource to obtain the requiered buffer sizes
        let (max_name, max_desc, num_sources) =
            self.alloc_info(safe::Environment::data_sources, direction)?;

        let mut source_list = Vec::with_capacity(num_sources);

        if num_sources > 0 {
            let mut name_buffer: Vec<_> = (0..(max_name + 1)).map(|_| 0u8).collect();
            let mut description_buffer: Vec<_> = (0..(max_desc + 1)).map(|_| 0u8).collect();

            // Before we call SQLDataSources with SQL_FETCH_NEXT, we have to call it with either
            // SQL_FETCH_FIRST, SQL_FETCH_FIRST_USER or SQL_FETCH_FIRST_SYSTEM, to get all, user or
            // system data sources
            if let Some((name, desc)) =
            self.get_info(
                safe::Environment::data_sources,
                direction,
                &mut name_buffer,
                &mut description_buffer,
            )?
                {
                    source_list.push(DataSourceInfo {
                        server_name: name.into_owned(),
                        driver: desc.into_owned(),
                })
            } else {
                return Ok(source_list);
            }

            while let Some((name, desc)) =
            self.get_info(
                safe::Environment::data_sources,
                ffi::SQL_FETCH_NEXT,
                &mut name_buffer,
                &mut description_buffer,
            )?
                {
                    source_list.push(DataSourceInfo {
                        server_name: name.into_owned(),
                        driver: desc.into_owned(),
                    })
                }
        }

        Ok(source_list)
    }

    /// Calls either SQLDrivers or SQLDataSources with the two given buffers and parses the result
    /// into a `(&str,&str)`
    fn get_info<'a, 'b>(
        &mut self,
        f: SqlInfoMethod,
        direction: ffi::FetchOrientation,
        buf1: &'a mut [u8],
        buf2: &'b mut [u8],
    ) -> Result<Option<(::std::borrow::Cow<'a, str>, ::std::borrow::Cow<'b, str>)>> {
        let result = f(&mut self.safe, direction, buf1, buf2);
        match try_into_option(result, self)? {
            Some((len1, len2)) => unsafe {
                Ok(Some((
                    ::environment::DB_ENCODING.decode(&buf1[0..(len1 as usize)]).0,
                    ::environment::DB_ENCODING.decode(&buf2[0..(len2 as usize)]).0,
                )))
            }
            None => Ok(None),
        }
    }

    /// Finds the maximum size required for description buffers
    fn alloc_info(
        &mut self,
        f: SqlInfoMethod,
        direction: ffi::FetchOrientation,
    ) -> Result<(ffi::SQLSMALLINT, ffi::SQLSMALLINT, usize)> {
        // In theory, we should use zero-length buffers here
        // However, if we do SQLDrivers gives us 0-length values for
        // the attributes length, which is incorrect, so we allocated a
        // reasonably large array which seems to make it do the right thing
        let mut string_buf1 = [0; 1024];
        let mut string_buf2 = [0; 1024];

        let mut max1 = 0;
        let mut max2 = 0;
        let mut count = 0;

        let mut result = f(
            &mut self.safe,
            direction,
            &mut string_buf1,
            &mut string_buf2,
        );

        loop {

            match result {
                safe::ReturnOption::Success((buf1_length_out, buf2_length_out)) |
                safe::ReturnOption::Info((buf1_length_out, buf2_length_out)) => {
                    count += 1;
                    max1 = max(max1, buf1_length_out);
                    max2 = max(max2, buf2_length_out);
                }
                safe::ReturnOption::NoData(()) => break,
                safe::ReturnOption::Error(()) => {
                    let diag = self.get_diag_rec(1).unwrap_or_else(DiagnosticRecord::empty);
                    error!("{}", diag);
                    return Err(diag);
                }
            }

            result = f(
                &mut self.safe,
                ffi::SQL_FETCH_NEXT,
                &mut string_buf1,
                &mut string_buf2,
            )
        }

        Ok((max1, max2, count))
    }
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn parse_attributes() {
        let buffer = "APILevel=2\0ConnectFunctions=YYY\0CPTimeout=60\0DriverODBCVer=03.\
                      50\0FileUsage=0\0SQLLevel=1\0UsageCount=1\0\0";
        let attributes = Environment::parse_attributes(buffer);
        assert_eq!(attributes["APILevel"], "2");
        assert_eq!(attributes["ConnectFunctions"], "YYY");
        assert_eq!(attributes["CPTimeout"], "60");
        assert_eq!(attributes["DriverODBCVer"], "03.50");
        assert_eq!(attributes["FileUsage"], "0");
        assert_eq!(attributes["SQLLevel"], "1");
        assert_eq!(attributes["UsageCount"], "1");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    adapter::local_storage::LocalStorage,
    backup::{backup_account_state, BackupServiceClient},
    restore::restore_account_state,
};
use backup_service::start_backup_service;
use libra_config::config::NodeConfig;
use libra_proptest_helpers::ValueGenerator;
use libra_temppath::TempPath;
use libra_types::transaction::PRE_GENESIS_VERSION;
use libradb::{test_helper::arb_blocks_to_commit, LibraDB};
use std::sync::Arc;
use storage_interface::{DbReader, DbWriter};

fn tmp_db_empty() -> (TempPath, LibraDB) {
    let tmpdir = TempPath::new();
    let db = LibraDB::new_for_test(&tmpdir);

    (tmpdir, db)
}

fn tmp_db_with_random_content() -> (TempPath, LibraDB) {
    let (tmpdir, db) = tmp_db_empty();
    let mut cur_ver = 0;
    for (txns_to_commit, ledger_info_with_sigs) in
        ValueGenerator::new().generate(arb_blocks_to_commit())
    {
        db.save_transactions(
            &txns_to_commit,
            cur_ver, /* first_version */
            Some(&ledger_info_with_sigs),
        )
        .unwrap();
        cur_ver += txns_to_commit.len() as u64;
    }

    (tmpdir, db)
}

#[test]
fn end_to_end() {
    let (_src_db_dir, db_src) = tmp_db_with_random_content();
    let db_src = Arc::new(db_src);
    let tgt_db_dir = TempPath::new();
    let backup_dir = TempPath::new();
    backup_dir.create_as_dir().unwrap();
    let adaptor = LocalStorage::new(backup_dir.path().to_path_buf());

    let config = NodeConfig::random();
    let mut rt = start_backup_service(config.storage.backup_service_port, db_src);
    let client = BackupServiceClient::new(config.storage.backup_service_port);
    let (version, state_root_hash) = rt.block_on(client.get_latest_state_root()).unwrap();
    let handles = rt
        .block_on(backup_account_state(&client, version, &adaptor, 500))
        .unwrap();

    rt.block_on(restore_account_state(
        PRE_GENESIS_VERSION,
        state_root_hash,
        &tgt_db_dir,
        handles.into_iter(),
    ))
    .unwrap();
    let tgt_db = LibraDB::open(
        &tgt_db_dir,
        true, /* readonly */
        None, /* pruner */
    )
    .unwrap();
    assert_eq!(
        tgt_db
            .get_latest_tree_state()
            .unwrap()
            .account_state_root_hash,
        state_root_hash,
    );
}
<commit_msg>[backup] trivial: name fix<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    adapter::local_storage::LocalStorage,
    backup::{backup_account_state, BackupServiceClient},
    restore::restore_account_state,
};
use backup_service::start_backup_service;
use libra_config::config::NodeConfig;
use libra_proptest_helpers::ValueGenerator;
use libra_temppath::TempPath;
use libra_types::transaction::PRE_GENESIS_VERSION;
use libradb::{test_helper::arb_blocks_to_commit, LibraDB};
use std::sync::Arc;
use storage_interface::{DbReader, DbWriter};

fn tmp_db_empty() -> (TempPath, LibraDB) {
    let tmpdir = TempPath::new();
    let db = LibraDB::new_for_test(&tmpdir);

    (tmpdir, db)
}

fn tmp_db_with_random_content() -> (TempPath, LibraDB) {
    let (tmpdir, db) = tmp_db_empty();
    let mut cur_ver = 0;
    for (txns_to_commit, ledger_info_with_sigs) in
        ValueGenerator::new().generate(arb_blocks_to_commit())
    {
        db.save_transactions(
            &txns_to_commit,
            cur_ver, /* first_version */
            Some(&ledger_info_with_sigs),
        )
        .unwrap();
        cur_ver += txns_to_commit.len() as u64;
    }

    (tmpdir, db)
}

#[test]
fn end_to_end() {
    let (_src_db_dir, src_db) = tmp_db_with_random_content();
    let src_db = Arc::new(src_db);
    let tgt_db_dir = TempPath::new();
    let backup_dir = TempPath::new();
    backup_dir.create_as_dir().unwrap();
    let adaptor = LocalStorage::new(backup_dir.path().to_path_buf());

    let config = NodeConfig::random();
    let mut rt = start_backup_service(config.storage.backup_service_port, src_db);
    let client = BackupServiceClient::new(config.storage.backup_service_port);
    let (version, state_root_hash) = rt.block_on(client.get_latest_state_root()).unwrap();
    let handles = rt
        .block_on(backup_account_state(&client, version, &adaptor, 500))
        .unwrap();

    rt.block_on(restore_account_state(
        PRE_GENESIS_VERSION,
        state_root_hash,
        &tgt_db_dir,
        handles.into_iter(),
    ))
    .unwrap();
    let tgt_db = LibraDB::open(
        &tgt_db_dir,
        true, /* readonly */
        None, /* pruner */
    )
    .unwrap();
    assert_eq!(
        tgt_db
            .get_latest_tree_state()
            .unwrap()
            .account_state_root_hash,
        state_root_hash,
    );
}
<|endoftext|>


<commit_before>//! Hello world server.
//!
//! A simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! You can test this out by running:
//!
//!     ncat -l 6142
//!
//! And then in another terminal run:
//!
//!     cargo run --example hello_world

#![warn(rust_2018_idioms)]

use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;

use std::error::Error;

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    // Open a TCP stream to the socket address.
    //
    // Note that this is the Tokio TcpStream, which is fully async.
    let mut stream = TcpStream::connect("127.0.0.1:6142").await?;
    println!("created stream");

    let result = stream.write_all(b"hello world\n").await;
    println!("wrote to stream; success={:?}", result.is_ok());

    Ok(())
}
<commit_msg>examples: update hello world comment (#5219)<commit_after>//! A simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! To start a server that this client can talk to on port 6142, you can use this command:
//!
//!     ncat -l 6142
//!
//! And then in another terminal run:
//!
//!     cargo run --example hello_world

#![warn(rust_2018_idioms)]

use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;

use std::error::Error;

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    // Open a TCP stream to the socket address.
    //
    // Note that this is the Tokio TcpStream, which is fully async.
    let mut stream = TcpStream::connect("127.0.0.1:6142").await?;
    println!("created stream");

    let result = stream.write_all(b"hello world\n").await;
    println!("wrote to stream; success={:?}", result.is_ok());

    Ok(())
}
<|endoftext|>


<commit_before>extern crate gnutls;

use gnutls::creds::{Cert, CredType};
use gnutls::{init, deinit, Session};

use std::io::prelude::*;
use std::os::unix::io::AsRawFd;
use std::net::TcpStream;

fn main() {
    match init() {
        Ok(_) => {},
        Err(_) => panic!("could not initialize.")
    };

    let host = ("bheesham.com", 443);
    let mut creds = Cert::new().unwrap();
    let mut session = Session::new(gnutls::GNUTLS_CLIENT).unwrap();

    if creds.x509_set_system_trust().err() != None {
        panic!("Error: couldn't set system trust.");
    }

    if creds.x509_set_key_file("../../gnutls/tests/ca.cert.pem",
                               "../../gnutls/tests/ca.noenckey.pem", None).err() != None {
        panic!("Error: couldn't set the keyfile.");
    }

    match session.set_priority(None) {
        Err(e) => panic!("{}", e),
        Ok(_) => {}
    };

    if session.set_creds(CredType::GNUTLS_CRD_CERTIFICATE, &mut creds) .err() != None {
        panic!("Error: could not set the session credentials.");
    }

    session.set_verify_cert(host.0, None);

    let mut stream = match TcpStream::connect(host) {
        Err(e) => panic!("{}", e),
        Ok(s) => s
    };

    session.set_fd(stream.as_raw_fd());
    session.handshake_timeout(None);

    match session.handshake() {
        Ok(_) => println!("Established a connection!"),
        Err(e) => panic!("Error: {}", e)
    };

    let _ = stream.write("GET / HTTP/1.0\n\n".as_bytes()).unwrap();

    let mut res = String::new();
    let _ = stream.read_to_string(&mut res).unwrap();
    println!("{}", res);

    deinit();
}
<commit_msg>Fix whitespace<commit_after>extern crate gnutls;

use gnutls::creds::{Cert, CredType};
use gnutls::{init, deinit, Session};

use std::io::prelude::*;
use std::os::unix::io::AsRawFd;
use std::net::TcpStream;

fn main() {
    match init() {
        Ok(_) => {},
        Err(_) => panic!("could not initialize.")
    };

    let host = ("bheesham.com", 443);
    let mut creds = Cert::new().unwrap();
    let mut session = Session::new(gnutls::GNUTLS_CLIENT).unwrap();

    if creds.x509_set_system_trust().err() != None {
        panic!("Error: couldn't set system trust.");
    }

    if creds.x509_set_key_file("../../gnutls/tests/ca.cert.pem",
                               "../../gnutls/tests/ca.noenckey.pem", None).err() != None {
        panic!("Error: couldn't set the keyfile.");
    }

    match session.set_priority(None) {
        Err(e) => panic!("{}", e),
        Ok(_) => {}
    };

    if session.set_creds(CredType::GNUTLS_CRD_CERTIFICATE, &mut creds).err() != None {
        panic!("Error: could not set the session credentials.");
    }

    session.set_verify_cert(host.0, None);

    let mut stream = match TcpStream::connect(host) {
        Err(e) => panic!("{}", e),
        Ok(s) => s
    };

    session.set_fd(stream.as_raw_fd());
    session.handshake_timeout(None);

    match session.handshake() {
        Ok(_) => println!("Established a connection!"),
        Err(e) => panic!("Error: {}", e)
    };

    let _ = stream.write("GET / HTTP/1.0\n\n".as_bytes()).unwrap();

    let mut res = String::new();
    let _ = stream.read_to_string(&mut res).unwrap();
    println!("{}", res);

    deinit();
}
<|endoftext|>


<commit_before>extern crate test;
extern crate murmurhash64;

use test::Bencher;
use murmurhash64::murmur_hash64a;

#[bench]
fn benchmark_murmur(b: &mut Bencher) {
    let key = "lorem ipsum dolor sit amet".as_bytes();
    let seed = 0xadc83b19;
    b.iter(|| {
        murmur_hash64a(key, seed);
    })
}
<commit_msg>More benchmarks<commit_after>#![feature(test)]

extern crate test;
extern crate murmurhash64;

use test::Bencher;
use murmurhash64::murmur_hash64a;

#[bench]
fn benchmark_murmur(b: &mut Bencher) {
    let key = "lorem ipsum dolor sit amet".as_bytes();
    let seed = 0xadc83b19;
    b.iter(|| {
        murmur_hash64a(key, seed);
    })
}

#[cfg(test)]
mod bench {
    extern crate test;

    use std::hash::Hasher;
    use murmurhash64::MurmurHasher;

    fn hasher_bench<H>(b: &mut test::Bencher, mut hasher: H, len: usize)
        where H: Hasher
    {
        let bytes: Vec<_> = (0..100).cycle().take(len).collect();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            hasher.write(&bytes);
            hasher.finish()
        });
    }

    fn murmurhash_bench(b: &mut test::Bencher, len: usize) {
        hasher_bench(b, MurmurHasher::with_seed(0), len)
    }

    #[bench]
    fn murmurhash_megabyte(b: &mut test::Bencher) { murmurhash_bench(b, 1024*1024) }

    #[bench]
    fn murmurhash_1024_byte(b: &mut test::Bencher) { murmurhash_bench(b, 1024) }

    #[bench]
    fn murmurhash_512_byte(b: &mut test::Bencher) { murmurhash_bench(b, 512) }

    #[bench]
    fn murmurhash_256_byte(b: &mut test::Bencher) { murmurhash_bench(b, 256) }

    #[bench]
    fn murmurhash_128_byte(b: &mut test::Bencher) { murmurhash_bench(b, 128) }

    #[bench]
    fn murmurhash_32_byte(b: &mut test::Bencher) { murmurhash_bench(b, 32) }

    #[bench]
    fn murmurhash_16_byte(b: &mut test::Bencher) { murmurhash_bench(b, 16) }

    #[bench]
    fn murmurhash_4_byte(b: &mut test::Bencher) { murmurhash_bench(b, 4) }

    #[bench]
    fn murmurhash_1_byte(b: &mut test::Bencher) { murmurhash_bench(b, 1) }

    #[bench]
    fn murmurhash_0_byte(b: &mut test::Bencher) { murmurhash_bench(b, 0) }
}
<|endoftext|>


<commit_before>use super::permutate::Permutator;
use smallvec::SmallVec;
use std::iter::Extend;

#[derive(Debug)]
/// A token primitive for the `expand_braces` function.
pub(crate) enum BraceToken {
    Normal(String),
    Expander,
}

pub(crate) fn expand_braces<'a>(
    tokens: &'a [BraceToken],
    expanders: &'a [&'a [&'a str]],
) -> Box<Iterator<Item = String> + 'a> {
    if expanders.len() > 1 {
        let multiple_brace_expand = MultipleBraceExpand {
            permutator: Permutator::new(expanders),
            tokens,
        };
        Box::new(multiple_brace_expand)
    } else if expanders.len() == 1 {
        let single_brace_expand = SingleBraceExpand {
            elements:   expanders[0].iter().map(|element| *element),
            tokens,
            loop_count: 0,
        };
        Box::new(single_brace_expand)
    } else {
        Box::new(::std::iter::empty())
    }
}

fn escape_string(input: &str) -> String {
    let mut output = String::new();
    let mut backslash = false;
    for character in input.chars() {
        if backslash {
            match character {
                '{' | '}' | ',' => output.push(character),
                _ => {
                    output.push('\\');
                    output.push(character);
                }
            }
            backslash = false;
        } else if character == '\\' {
            backslash = true;
        } else {
            output.push(character);
        }
    }
    output
}

pub struct MultipleBraceExpand<'a, 'b> {
    permutator: Permutator<'a, str>,
    tokens:     &'b [BraceToken],
}

impl<'a, 'b> Iterator for MultipleBraceExpand<'a, 'b> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(permutation) = self.permutator.next() {
            let mut strings = permutation.iter();
            let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                SmallVec::with_capacity(64),
                |mut small_vec, token| match *token {
                    BraceToken::Normal(ref text) => {
                        small_vec.extend(escape_string(text).bytes());
                        small_vec
                    }
                    BraceToken::Expander => {
                        small_vec.extend(escape_string(strings.next().unwrap()).bytes());
                        small_vec
                    }
                },
            );
            Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
        } else {
            None
        }
    }
}

pub struct SingleBraceExpand<'a, 'b, I>
where
    I: Iterator<Item = &'a str>,
{
    elements:   I,
    tokens:     &'b [BraceToken],
    loop_count: usize,
}

impl<'a, 'b, I> Iterator for SingleBraceExpand<'a, 'b, I>
where
    I: Iterator<Item = &'a str>,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        match self.loop_count {
            0 => {
                let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                    SmallVec::with_capacity(64),
                    |mut small_vec, token| match *token {
                        BraceToken::Normal(ref text) => {
                            small_vec.extend(escape_string(text).bytes());
                            small_vec
                        }
                        BraceToken::Expander => {
                            small_vec.extend(escape_string(self.elements.next().unwrap()).bytes());
                            small_vec
                        }
                    },
                );
                self.loop_count = 1;
                Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
            }
            _ => {
                if let Some(element) = self.elements.next() {
                    let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                        SmallVec::with_capacity(64),
                        |mut small_vec, token| match *token {
                            BraceToken::Normal(ref text) => {
                                small_vec.extend(escape_string(text).bytes());
                                small_vec
                            }
                            BraceToken::Expander => {
                                small_vec.extend(escape_string(element).bytes());
                                small_vec
                            }
                        },
                    );
                    Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
                } else {
                    None
                }
            }
        }
    }
}

#[test]
fn test_multiple_brace_expand() {
    let expanders: &[&[&str]] = &[&["1", "2"][..], &["3", "4"][..], &["5", "6"][..]];
    let tokens: &[BraceToken] = &[
        BraceToken::Normal("AB".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("CD".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("EF".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("GH".to_owned()),
    ];
    assert_eq!(
        MultipleBraceExpand {
            permutator: Permutator::new(expanders),
            tokens,
        }.collect::<Vec<String>>(),
        vec![
            "AB1CD3EF5GH".to_owned(),
            "AB1CD3EF6GH".to_owned(),
            "AB1CD4EF5GH".to_owned(),
            "AB1CD4EF6GH".to_owned(),
            "AB2CD3EF5GH".to_owned(),
            "AB2CD3EF6GH".to_owned(),
            "AB2CD4EF5GH".to_owned(),
            "AB2CD4EF6GH".to_owned(),
        ]
    );
}

#[test]
fn test_single_brace_expand() {
    let elements = &["one", "two", "three"];
    let tokens: &[BraceToken] = &[BraceToken::Normal("A=".to_owned()), BraceToken::Expander];
    assert_eq!(
        SingleBraceExpand {
            elements:   elements.iter().map(|element| *element),
            tokens,
            loop_count: 0,
        }.collect::<Vec<String>>(),
        vec!["A=one".to_owned(), "A=two".to_owned(), "A=three".to_owned()]
    );
}
<commit_msg>Reduce brace expansion allocations (#741)<commit_after>use super::permutate::Permutator;
use smallvec::SmallVec;

#[derive(Debug)]
/// A token primitive for the `expand_braces` function.
pub(crate) enum BraceToken {
    Normal(String),
    Expander,
}

pub(crate) fn expand_braces<'a>(
    tokens: &'a [BraceToken],
    expanders: &'a [&'a [&'a str]],
) -> Box<Iterator<Item = String> + 'a> {
    if expanders.len() > 1 {
        let multiple_brace_expand = MultipleBraceExpand::new(tokens, expanders);
        Box::new(multiple_brace_expand)
    } else if expanders.len() == 1 {
        let single_brace_expand = SingleBraceExpand {
            elements:   expanders[0].iter().map(|element| *element),
            tokens,
            loop_count: 0,
        };
        Box::new(single_brace_expand)
    } else {
        Box::new(::std::iter::empty())
    }
}

fn escape_string(output: &mut SmallVec<[u8; 64]>, input: &str) {
    let mut backslash = false;
    for character in input.bytes() {
        if backslash {
            match character {
                b'{' | b'}' | b',' => output.push(character),
                _ => {
                    output.push(b'\\');
                    output.push(character);
                }
            }
            backslash = false;
        } else if character == b'\\' {
            backslash = true;
        } else {
            output.push(character);
        }
    }
}

pub struct MultipleBraceExpand<'a> {
    permutator: Permutator<'a, str>,
    tokens:     &'a [BraceToken],
    buffer:     Vec<&'a str>
}

impl<'a> MultipleBraceExpand<'a> {
    pub(crate) fn new(
        tokens: &'a [BraceToken],
        expanders: &'a [&'a [&'a str]]
    ) -> MultipleBraceExpand<'a> {
        MultipleBraceExpand {
            permutator: Permutator::new(expanders),
            tokens,
            buffer: vec![""; expanders.len()]
        }
    }
}

impl<'a> Iterator for MultipleBraceExpand<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.permutator.next_with_buffer(&mut self.buffer) {
            let mut strings = self.buffer.iter();
            let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                SmallVec::with_capacity(64),
                |mut small_vec, token| match *token {
                    BraceToken::Normal(ref text) => {
                        escape_string(&mut small_vec, text);
                        small_vec
                    }
                    BraceToken::Expander => {
                        escape_string(&mut small_vec, strings.next().unwrap());
                        small_vec
                    }
                },
            );
            Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
        } else {
            None
        }
    }
}

pub struct SingleBraceExpand<'a, 'b, I>
where
    I: Iterator<Item = &'a str>,
{
    elements:   I,
    tokens:     &'b [BraceToken],
    loop_count: usize,
}

impl<'a, 'b, I> Iterator for SingleBraceExpand<'a, 'b, I>
where
    I: Iterator<Item = &'a str>,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        match self.loop_count {
            0 => {
                let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                    SmallVec::with_capacity(64),
                    |mut small_vec, token| match *token {
                        BraceToken::Normal(ref text) => {
                            escape_string(&mut small_vec, text);
                            small_vec
                        }
                        BraceToken::Expander => {
                            escape_string(&mut small_vec, self.elements.next().unwrap());
                            small_vec
                        }
                    },
                );
                self.loop_count = 1;
                Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
            }
            _ => {
                if let Some(element) = self.elements.next() {
                    let small_vec: SmallVec<[u8; 64]> = self.tokens.iter().fold(
                        SmallVec::with_capacity(64),
                        |mut small_vec, token| match *token {
                            BraceToken::Normal(ref text) => {
                                escape_string(&mut small_vec, text);
                                small_vec
                            }
                            BraceToken::Expander => {
                                escape_string(&mut small_vec, element);
                                small_vec
                            }
                        },
                    );
                    Some(unsafe { String::from_utf8_unchecked(small_vec.to_vec()) })
                } else {
                    None
                }
            }
        }
    }
}

#[test]
fn test_multiple_brace_expand() {
    let expanders: &[&[&str]] = &[&["1", "2"][..], &["3", "4"][..], &["5", "6"][..]];
    let tokens: &[BraceToken] = &[
        BraceToken::Normal("AB".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("CD".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("EF".to_owned()),
        BraceToken::Expander,
        BraceToken::Normal("GH".to_owned()),
    ];
    assert_eq!(
        MultipleBraceExpand ::new(tokens, expanders).collect::<Vec<String>>(),
        vec![
            "AB1CD3EF5GH".to_owned(),
            "AB1CD3EF6GH".to_owned(),
            "AB1CD4EF5GH".to_owned(),
            "AB1CD4EF6GH".to_owned(),
            "AB2CD3EF5GH".to_owned(),
            "AB2CD3EF6GH".to_owned(),
            "AB2CD4EF5GH".to_owned(),
            "AB2CD4EF6GH".to_owned(),
        ]
    );
}

#[test]
fn test_single_brace_expand() {
    let elements = &["one", "two", "three"];
    let tokens: &[BraceToken] = &[BraceToken::Normal("A=".to_owned()), BraceToken::Expander];
    assert_eq!(
        SingleBraceExpand {
            elements:   elements.iter().map(|element| *element),
            tokens,
            loop_count: 0,
        }.collect::<Vec<String>>(),
        vec!["A=one".to_owned(), "A=two".to_owned(), "A=three".to_owned()]
    );
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
#[cfg(windows)]
use std::os::windows::fs as windows;
use std::path::Path;
use std::process;
#[cfg(windows)]
use std::{env, fs};

const MISSING: &str = "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When building `cxx` from a git clone, git's symlink support needs
to be enabled on platforms that have it off by default (Windows).
Either use:

   $ git config --global core.symlinks true

prior to cloning, or else use:

   $ git clone -c core.symlinks=true https://github.com/dtolnay/cxx

for the clone.

Symlinks are only required when compiling locally from a clone of
the git repository---they are NOT required when building `cxx` as
a Cargo-managed (possibly transitive) build dependency downloaded
through crates.io.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
";

#[cfg(windows)]
const DENIED: &str = "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When building `cxx` from a git clone on Windows we need Developer
Mode enabled for symlink support.

To enable Developer Mode: go under Settings to Update & Security,
then 'For developers', and turn on the toggle for Developer Mode.

For more explanation of symlinks in Windows, see these resources:
> https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
> https://docs.microsoft.com/windows/uwp/get-started/enable-your-device-for-development

Symlinks are only required when compiling locally from a clone of
the git repository---they are NOT required when building `cxx` as
a Cargo-managed (possibly transitive) build dependency downloaded
through crates.io.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
";

fn main() {
    if Path::new("src/syntax/mod.rs").exists() {
        return;
    }

    #[allow(unused_mut)]
    let mut message = MISSING;

    #[cfg(windows)]
    if let Some(out_dir) = env::var_os("OUT_DIR") {
        let parent_dir = Path::new(&out_dir).join("symlink");
        let from_dir = parent_dir.join("from");
        let to_dir = parent_dir.join("to");
        if fs::create_dir_all(&from_dir).is_ok()
            && fs::remove_dir(&to_dir).is_ok()
            && windows::symlink_dir(&from_dir, &to_dir).is_err()
        {
            message = DENIED;
        }
    }

    let _ = io::stderr().write_all(message.as_bytes());
    process::exit(1);
}
<commit_msg>Fix testing for symlink denied on initial builds<commit_after>use std::io::{self, Write};
#[cfg(windows)]
use std::os::windows::fs as windows;
use std::path::Path;
use std::process;
#[cfg(windows)]
use std::{env, fs};

const MISSING: &str = "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When building `cxx` from a git clone, git's symlink support needs
to be enabled on platforms that have it off by default (Windows).
Either use:

   $ git config --global core.symlinks true

prior to cloning, or else use:

   $ git clone -c core.symlinks=true https://github.com/dtolnay/cxx

for the clone.

Symlinks are only required when compiling locally from a clone of
the git repository---they are NOT required when building `cxx` as
a Cargo-managed (possibly transitive) build dependency downloaded
through crates.io.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
";

#[cfg(windows)]
const DENIED: &str = "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When building `cxx` from a git clone on Windows we need Developer
Mode enabled for symlink support.

To enable Developer Mode: go under Settings to Update & Security,
then 'For developers', and turn on the toggle for Developer Mode.

For more explanation of symlinks in Windows, see these resources:
> https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
> https://docs.microsoft.com/windows/uwp/get-started/enable-your-device-for-development

Symlinks are only required when compiling locally from a clone of
the git repository---they are NOT required when building `cxx` as
a Cargo-managed (possibly transitive) build dependency downloaded
through crates.io.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
";

fn main() {
    if Path::new("src/syntax/mod.rs").exists() {
        return;
    }

    #[allow(unused_mut)]
    let mut message = MISSING;

    #[cfg(windows)]
    if let Some(out_dir) = env::var_os("OUT_DIR") {
        let parent_dir = Path::new(&out_dir).join("symlink");
        let from_dir = parent_dir.join("from");
        let to_dir = parent_dir.join("to");
        if fs::create_dir_all(&from_dir).is_ok()
            && (!to_dir.exists() || fs::remove_dir(&to_dir).is_ok())
            && windows::symlink_dir(&from_dir, &to_dir).is_err()
        {
            message = DENIED;
        }
    }

    let _ = io::stderr().write_all(message.as_bytes());
    process::exit(1);
}
<|endoftext|>