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

use crate::canvas_data::{
    Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
    GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern,
    SourceSurface, StrokeOptions, SurfaceFormat,
};
use crate::canvas_paint_thread::AntialiasMode;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use std::marker::PhantomData;

pub struct RaqoteBackend;

impl Backend for RaqoteBackend {
    fn get_composition_op(&self, _opts: &DrawOptions) -> CompositionOp {
        unimplemented!()
    }

    fn need_to_draw_shadow(&self, color: &Color) -> bool {
        color.as_raqote().a != 0
    }

    fn size_from_pattern(&self, _rect: &Rect<f32>, _pattern: &Pattern) -> Option<Size2D<f32>> {
        unimplemented!()
    }

    fn set_shadow_color<'a>(&mut self, _color: RGBA, _state: &mut CanvasPaintState<'a>) {
        unimplemented!()
    }

    fn set_fill_style<'a>(
        &mut self,
        style: FillOrStrokeStyle,
        state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        if let Some(source) = style.to_raqote_source() {
            state.fill_style = Pattern::Raqote(source);
        }
    }

    fn set_stroke_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_global_composition<'a>(
        &mut self,
        _op: CompositionOrBlending,
        _state: &mut CanvasPaintState<'a>,
    ) {
        unimplemented!()
    }

    fn create_drawtarget(&self, size: Size2D<u64>) -> Box<dyn GenericDrawTarget> {
        Box::new(raqote::DrawTarget::new(
            size.width as i32,
            size.height as i32,
        ))
    }

    fn recreate_paint_state<'a>(&self, _state: &CanvasPaintState<'a>) -> CanvasPaintState<'a> {
        CanvasPaintState::new(AntialiasMode::Default)
    }
}

impl<'a> CanvasPaintState<'a> {
    pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
        let solid_src = raqote::SolidSource { r: 0, g: 0, b: 0, a: 255 };
        CanvasPaintState {
            draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
            fill_style: Pattern::Raqote(raqote::Source::Solid(solid_src)),
            stroke_style: Pattern::Raqote(raqote::Source::Solid(solid_src)),
            stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
            transform: Transform2D::identity(),
            shadow_offset_x: 0.0,
            shadow_offset_y: 0.0,
            shadow_blur: 0.0,
            shadow_color: Color::Raqote(raqote::SolidSource { r: 0, g: 0, b: 0, a: 0 }),
        }
    }
}

impl Pattern<'_> {
    pub fn is_zero_size_gradient(&self) -> bool {
        match self {
            Pattern::Raqote(p) => {
                use raqote::Source::*;

                match p {
                    LinearGradient(g, ..) | RadialGradient(g, ..) | TwoCircleRadialGradient(g, ..) => {
                        g.stops.is_empty()
                    },
                    _ => false
                }
            },
        }
    }
    pub fn as_raqote(&self) -> &raqote::Source {
        match self {
            Pattern::Raqote(p) => p,
        }
    }
}

impl<'a> StrokeOptions<'a> {
    pub fn set_line_width(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.width = _val,
        }
    }
    pub fn set_miter_limit(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.miter_limit = _val,
        }
    }
    pub fn set_line_join(&mut self, _val: LineJoinStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.join = _val.to_raqote_style(),
        }
    }
    pub fn set_line_cap(&mut self, _val: LineCapStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.cap = _val.to_raqote_style(),
        }
    }
    pub fn as_raqote(&self) -> &raqote::StrokeStyle {
        match self {
            StrokeOptions::Raqote(options, _) => options,
        }
    }
}

impl DrawOptions {
    pub fn set_alpha(&mut self, _val: f32) {
        match self {
            DrawOptions::Raqote(draw_options) => draw_options.alpha = _val,
        }
    }
    pub fn as_raqote(&self) -> &raqote::DrawOptions {
        match self {
            DrawOptions::Raqote(options) => options,
        }
    }
}

impl Path {
    pub fn transformed_copy_to_builder(
        &self,
        _transform: &Transform2D<f32>,
    ) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn contains_point(&self, _x: f64, _y: f64, _path_transform: &Transform2D<f32>) -> bool {
        unimplemented!()
    }

    pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn as_raqote(&self) -> &raqote::Path {
        match self {
            Path::Raqote(p) => p,
        }
    }
}

impl GenericDrawTarget for raqote::DrawTarget {
    fn clear_rect(&self, _rect: &Rect<f32>) {
        unimplemented!();
    }
    fn copy_surface(
        &mut self,
        _surface: SourceSurface,
        _source: Rect<i32>,
        _destination: Point2D<i32>,
    ) {
        unimplemented!();
    }
    fn create_gradient_stops(
        &self,
        _gradient_stops: Vec<GradientStop>,
        _extend_mode: ExtendMode,
    ) -> GradientStops {
        unimplemented!();
    }
    fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
        Box::new(PathBuilder::new())
    }
    fn create_similar_draw_target(
        &self,
        _size: &Size2D<i32>,
        _format: SurfaceFormat,
    ) -> Box<dyn GenericDrawTarget> {
        unimplemented!();
    }
    fn create_source_surface_from_data(
        &self,
        _data: &[u8],
        _size: Size2D<i32>,
        _stride: i32,
    ) -> Option<SourceSurface> {
        unimplemented!();
    }
    fn draw_surface(
        &self,
        _surface: SourceSurface,
        _dest: Rect<f64>,
        _source: Rect<f64>,
        _filter: Filter,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    fn draw_surface_with_shadow(
        &self,
        _surface: SourceSurface,
        _dest: &Point2D<f32>,
        _color: &Color,
        _offset: &Vector2D<f32>,
        _sigma: f32,
        _operator: CompositionOp,
    ) {
        unimplemented!();
    }
    fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) {
        self.fill(path.as_raqote(), pattern.as_raqote(), draw_options.as_raqote());
    }
    fn fill_rect(
        &mut self,
        rect: &Rect<f32>,
        pattern: Pattern,
        _draw_options: Option<&DrawOptions>,
    ) {
        let mut pb = raqote::PathBuilder::new();
        pb.rect(
            rect.origin.x,
            rect.origin.y,
            rect.size.width,
            rect.size.height,
        );
        raqote::DrawTarget::fill(
            self,
            &pb.finish(),
            pattern.as_raqote(),
            &raqote::DrawOptions::new(),
        );
    }
    fn get_format(&self) -> SurfaceFormat {
        unimplemented!();
    }
    fn get_size(&self) -> Size2D<i32> {
        unimplemented!();
    }
    fn get_transform(&self) -> Transform2D<f32> {
        *self.get_transform()
    }
    fn pop_clip(&mut self) {
        self.pop_clip();
    }
    fn push_clip(&mut self, path: &Path) {
        self.push_clip(path.as_raqote());
    }
    fn set_transform(&mut self, matrix: &Transform2D<f32>) {
        self.set_transform(matrix);
    }
    fn snapshot(&self) -> SourceSurface {
        unimplemented!();
    }
    fn stroke(
        &mut self,
        path: &Path,
        pattern: Pattern,
        stroke_options: &StrokeOptions,
        draw_options: &DrawOptions,
    ) {
        self.stroke(
            path.as_raqote(),
            pattern.as_raqote(),
            stroke_options.as_raqote(),
            draw_options.as_raqote(),
            );
    }
    fn stroke_line(
        &mut self,
        _start: Point2D<f32>,
        _end: Point2D<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    fn stroke_rect(
        &mut self,
        _rect: &Rect<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    #[allow(unsafe_code)]
    fn snapshot_data(&self, f: &dyn Fn(&[u8]) -> Vec<u8>) -> Vec<u8> {
        let v = self.get_data();
        f(unsafe {
            std::slice::from_raw_parts(
                v.as_ptr() as *const u8,
                v.len() * std::mem::size_of::<u32>(),
            )
        })
    }
    fn snapshot_data_owned(&self) -> Vec<u8> {
        unimplemented!();
    }
}

struct PathBuilder(Option<raqote::PathBuilder>);

impl PathBuilder {
    fn new() -> PathBuilder {
        PathBuilder(Some(raqote::PathBuilder::new()))
    }
}

impl GenericPathBuilder for PathBuilder {
    fn arc(
        &mut self,
        origin: Point2D<f32>,
        radius: f32,
        start_angle: f32,
        end_angle: f32,
        _anticlockwise: bool,
    ) {
        self.0.as_mut().unwrap().arc(origin.x, origin.y, radius, start_angle, end_angle);
    }
    fn bezier_curve_to(
        &mut self,
        control_point1: &Point2D<f32>,
        control_point2: &Point2D<f32>,
        control_point3: &Point2D<f32>,
    ) {
        self.0.as_mut().unwrap().cubic_to(
            control_point1.x,
            control_point1.y,
            control_point2.x,
            control_point2.y,
            control_point3.x,
            control_point3.y,
        );
    }
    fn close(&mut self) {
        self.0.as_mut().unwrap().close();
    }
    fn ellipse(
        &mut self,
        _origin: Point2D<f32>,
        _radius_x: f32,
        _radius_y: f32,
        _rotation_angle: f32,
        _start_angle: f32,
        _end_angle: f32,
        _anticlockwise: bool,
    ) {
        unimplemented!();
    }
    fn get_current_point(&mut self) -> Point2D<f32> {
        unimplemented!();
    }
    fn line_to(&mut self, point: Point2D<f32>) {
        self.0.as_mut().unwrap().line_to(point.x, point.y);
    }
    fn move_to(&mut self, point: Point2D<f32>) {
        self.0.as_mut().unwrap().move_to(point.x, point.y);
    }
    fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, end_point: &Point2D<f32>) {
        self.0.as_mut().unwrap().quad_to(control_point.x, control_point.y, end_point.x, end_point.y);
    }
    fn finish(&mut self) -> Path {
        Path::Raqote(self.0.take().unwrap().finish())
    }
}

pub trait ToRaqoteStyle {
    type Target;

    fn to_raqote_style(self) -> Self::Target;
}

impl ToRaqoteStyle for LineJoinStyle {
    type Target = raqote::LineJoin;

    fn to_raqote_style(self) -> raqote::LineJoin {
        match self {
            LineJoinStyle::Round => raqote::LineJoin::Round,
            LineJoinStyle::Bevel => raqote::LineJoin::Bevel,
            LineJoinStyle::Miter => raqote::LineJoin::Miter,
        }
    }
}

impl ToRaqoteStyle for LineCapStyle {
    type Target = raqote::LineCap;

    fn to_raqote_style(self) -> raqote::LineCap {
        match self {
            LineCapStyle::Butt => raqote::LineCap::Butt,
            LineCapStyle::Round => raqote::LineCap::Round,
            LineCapStyle::Square => raqote::LineCap::Square,
        }
    }
}

// TODO(pylbrecht)
#[cfg(feature = "raqote_backend")]
impl Clone for Pattern<'_> {
    fn clone(&self) -> Self {
        unimplemented!();
    }
}

pub trait ToRaqoteSource<'a> {
    fn to_raqote_source(self) -> Option<raqote::Source<'a>>;
}

impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle {
    fn to_raqote_source(self) -> Option<raqote::Source<'a>> {
        use canvas_traits::canvas::FillOrStrokeStyle::*;

        match self {
            Color(rgba) => Some(raqote::Source::Solid(raqote::SolidSource {
                r: rgba.red,
                g: rgba.green,
                b: rgba.blue,
                a: rgba.alpha,
            })),
            LinearGradient(_) => unimplemented!(),
            RadialGradient(_) => unimplemented!(),
            Surface(_) => unimplemented!(),
        }
    }
}

impl Color {
    fn as_raqote(&self) -> &raqote::SolidSource {
        match self {
            Color::Raqote(s) => s,
        }
    }
}
<commit_msg>Implement size_from_pattern<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::canvas_data::{
    Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
    GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern,
    SourceSurface, StrokeOptions, SurfaceFormat,
};
use crate::canvas_paint_thread::AntialiasMode;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use std::marker::PhantomData;

pub struct RaqoteBackend;

impl Backend for RaqoteBackend {
    fn get_composition_op(&self, _opts: &DrawOptions) -> CompositionOp {
        unimplemented!()
    }

    fn need_to_draw_shadow(&self, color: &Color) -> bool {
        color.as_raqote().a != 0
    }

    fn size_from_pattern(&self, rect: &Rect<f32>, pattern: &Pattern) -> Option<Size2D<f32>> {
        match pattern {
            Pattern::Raqote(raqote::Source::Image(image, extend, ..)) => {
                match extend {
                    raqote::ExtendMode::Repeat => {
                        Some(rect.size)
                    },
                    _ => Some(Size2D::new(image.width as f32, image.height as f32))
                }
            },
            _ => None
        }
    }

    fn set_shadow_color<'a>(&mut self, _color: RGBA, _state: &mut CanvasPaintState<'a>) {
        unimplemented!()
    }

    fn set_fill_style<'a>(
        &mut self,
        style: FillOrStrokeStyle,
        state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        if let Some(source) = style.to_raqote_source() {
            state.fill_style = Pattern::Raqote(source);
        }
    }

    fn set_stroke_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_global_composition<'a>(
        &mut self,
        _op: CompositionOrBlending,
        _state: &mut CanvasPaintState<'a>,
    ) {
        unimplemented!()
    }

    fn create_drawtarget(&self, size: Size2D<u64>) -> Box<dyn GenericDrawTarget> {
        Box::new(raqote::DrawTarget::new(
            size.width as i32,
            size.height as i32,
        ))
    }

    fn recreate_paint_state<'a>(&self, _state: &CanvasPaintState<'a>) -> CanvasPaintState<'a> {
        CanvasPaintState::new(AntialiasMode::Default)
    }
}

impl<'a> CanvasPaintState<'a> {
    pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
        let solid_src = raqote::SolidSource { r: 0, g: 0, b: 0, a: 255 };
        CanvasPaintState {
            draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
            fill_style: Pattern::Raqote(raqote::Source::Solid(solid_src)),
            stroke_style: Pattern::Raqote(raqote::Source::Solid(solid_src)),
            stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
            transform: Transform2D::identity(),
            shadow_offset_x: 0.0,
            shadow_offset_y: 0.0,
            shadow_blur: 0.0,
            shadow_color: Color::Raqote(raqote::SolidSource { r: 0, g: 0, b: 0, a: 0 }),
        }
    }
}

impl Pattern<'_> {
    pub fn is_zero_size_gradient(&self) -> bool {
        match self {
            Pattern::Raqote(p) => {
                use raqote::Source::*;

                match p {
                    LinearGradient(g, ..) | RadialGradient(g, ..) | TwoCircleRadialGradient(g, ..) => {
                        g.stops.is_empty()
                    },
                    _ => false
                }
            },
        }
    }
    pub fn as_raqote(&self) -> &raqote::Source {
        match self {
            Pattern::Raqote(p) => p,
        }
    }
}

impl<'a> StrokeOptions<'a> {
    pub fn set_line_width(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.width = _val,
        }
    }
    pub fn set_miter_limit(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.miter_limit = _val,
        }
    }
    pub fn set_line_join(&mut self, _val: LineJoinStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.join = _val.to_raqote_style(),
        }
    }
    pub fn set_line_cap(&mut self, _val: LineCapStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.cap = _val.to_raqote_style(),
        }
    }
    pub fn as_raqote(&self) -> &raqote::StrokeStyle {
        match self {
            StrokeOptions::Raqote(options, _) => options,
        }
    }
}

impl DrawOptions {
    pub fn set_alpha(&mut self, _val: f32) {
        match self {
            DrawOptions::Raqote(draw_options) => draw_options.alpha = _val,
        }
    }
    pub fn as_raqote(&self) -> &raqote::DrawOptions {
        match self {
            DrawOptions::Raqote(options) => options,
        }
    }
}

impl Path {
    pub fn transformed_copy_to_builder(
        &self,
        _transform: &Transform2D<f32>,
    ) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn contains_point(&self, _x: f64, _y: f64, _path_transform: &Transform2D<f32>) -> bool {
        unimplemented!()
    }

    pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn as_raqote(&self) -> &raqote::Path {
        match self {
            Path::Raqote(p) => p,
        }
    }
}

impl GenericDrawTarget for raqote::DrawTarget {
    fn clear_rect(&self, _rect: &Rect<f32>) {
        unimplemented!();
    }
    fn copy_surface(
        &mut self,
        _surface: SourceSurface,
        _source: Rect<i32>,
        _destination: Point2D<i32>,
    ) {
        unimplemented!();
    }
    fn create_gradient_stops(
        &self,
        _gradient_stops: Vec<GradientStop>,
        _extend_mode: ExtendMode,
    ) -> GradientStops {
        unimplemented!();
    }
    fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
        Box::new(PathBuilder::new())
    }
    fn create_similar_draw_target(
        &self,
        _size: &Size2D<i32>,
        _format: SurfaceFormat,
    ) -> Box<dyn GenericDrawTarget> {
        unimplemented!();
    }
    fn create_source_surface_from_data(
        &self,
        _data: &[u8],
        _size: Size2D<i32>,
        _stride: i32,
    ) -> Option<SourceSurface> {
        unimplemented!();
    }
    fn draw_surface(
        &self,
        _surface: SourceSurface,
        _dest: Rect<f64>,
        _source: Rect<f64>,
        _filter: Filter,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    fn draw_surface_with_shadow(
        &self,
        _surface: SourceSurface,
        _dest: &Point2D<f32>,
        _color: &Color,
        _offset: &Vector2D<f32>,
        _sigma: f32,
        _operator: CompositionOp,
    ) {
        unimplemented!();
    }
    fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) {
        self.fill(path.as_raqote(), pattern.as_raqote(), draw_options.as_raqote());
    }
    fn fill_rect(
        &mut self,
        rect: &Rect<f32>,
        pattern: Pattern,
        _draw_options: Option<&DrawOptions>,
    ) {
        let mut pb = raqote::PathBuilder::new();
        pb.rect(
            rect.origin.x,
            rect.origin.y,
            rect.size.width,
            rect.size.height,
        );
        raqote::DrawTarget::fill(
            self,
            &pb.finish(),
            pattern.as_raqote(),
            &raqote::DrawOptions::new(),
        );
    }
    fn get_format(&self) -> SurfaceFormat {
        unimplemented!();
    }
    fn get_size(&self) -> Size2D<i32> {
        unimplemented!();
    }
    fn get_transform(&self) -> Transform2D<f32> {
        *self.get_transform()
    }
    fn pop_clip(&mut self) {
        self.pop_clip();
    }
    fn push_clip(&mut self, path: &Path) {
        self.push_clip(path.as_raqote());
    }
    fn set_transform(&mut self, matrix: &Transform2D<f32>) {
        self.set_transform(matrix);
    }
    fn snapshot(&self) -> SourceSurface {
        unimplemented!();
    }
    fn stroke(
        &mut self,
        path: &Path,
        pattern: Pattern,
        stroke_options: &StrokeOptions,
        draw_options: &DrawOptions,
    ) {
        self.stroke(
            path.as_raqote(),
            pattern.as_raqote(),
            stroke_options.as_raqote(),
            draw_options.as_raqote(),
            );
    }
    fn stroke_line(
        &mut self,
        _start: Point2D<f32>,
        _end: Point2D<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    fn stroke_rect(
        &mut self,
        _rect: &Rect<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!();
    }
    #[allow(unsafe_code)]
    fn snapshot_data(&self, f: &dyn Fn(&[u8]) -> Vec<u8>) -> Vec<u8> {
        let v = self.get_data();
        f(unsafe {
            std::slice::from_raw_parts(
                v.as_ptr() as *const u8,
                v.len() * std::mem::size_of::<u32>(),
            )
        })
    }
    fn snapshot_data_owned(&self) -> Vec<u8> {
        unimplemented!();
    }
}

struct PathBuilder(Option<raqote::PathBuilder>);

impl PathBuilder {
    fn new() -> PathBuilder {
        PathBuilder(Some(raqote::PathBuilder::new()))
    }
}

impl GenericPathBuilder for PathBuilder {
    fn arc(
        &mut self,
        origin: Point2D<f32>,
        radius: f32,
        start_angle: f32,
        end_angle: f32,
        _anticlockwise: bool,
    ) {
        self.0.as_mut().unwrap().arc(origin.x, origin.y, radius, start_angle, end_angle);
    }
    fn bezier_curve_to(
        &mut self,
        control_point1: &Point2D<f32>,
        control_point2: &Point2D<f32>,
        control_point3: &Point2D<f32>,
    ) {
        self.0.as_mut().unwrap().cubic_to(
            control_point1.x,
            control_point1.y,
            control_point2.x,
            control_point2.y,
            control_point3.x,
            control_point3.y,
        );
    }
    fn close(&mut self) {
        self.0.as_mut().unwrap().close();
    }
    fn ellipse(
        &mut self,
        _origin: Point2D<f32>,
        _radius_x: f32,
        _radius_y: f32,
        _rotation_angle: f32,
        _start_angle: f32,
        _end_angle: f32,
        _anticlockwise: bool,
    ) {
        unimplemented!();
    }
    fn get_current_point(&mut self) -> Point2D<f32> {
        unimplemented!();
    }
    fn line_to(&mut self, point: Point2D<f32>) {
        self.0.as_mut().unwrap().line_to(point.x, point.y);
    }
    fn move_to(&mut self, point: Point2D<f32>) {
        self.0.as_mut().unwrap().move_to(point.x, point.y);
    }
    fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, end_point: &Point2D<f32>) {
        self.0.as_mut().unwrap().quad_to(control_point.x, control_point.y, end_point.x, end_point.y);
    }
    fn finish(&mut self) -> Path {
        Path::Raqote(self.0.take().unwrap().finish())
    }
}

pub trait ToRaqoteStyle {
    type Target;

    fn to_raqote_style(self) -> Self::Target;
}

impl ToRaqoteStyle for LineJoinStyle {
    type Target = raqote::LineJoin;

    fn to_raqote_style(self) -> raqote::LineJoin {
        match self {
            LineJoinStyle::Round => raqote::LineJoin::Round,
            LineJoinStyle::Bevel => raqote::LineJoin::Bevel,
            LineJoinStyle::Miter => raqote::LineJoin::Miter,
        }
    }
}

impl ToRaqoteStyle for LineCapStyle {
    type Target = raqote::LineCap;

    fn to_raqote_style(self) -> raqote::LineCap {
        match self {
            LineCapStyle::Butt => raqote::LineCap::Butt,
            LineCapStyle::Round => raqote::LineCap::Round,
            LineCapStyle::Square => raqote::LineCap::Square,
        }
    }
}

// TODO(pylbrecht)
#[cfg(feature = "raqote_backend")]
impl Clone for Pattern<'_> {
    fn clone(&self) -> Self {
        unimplemented!();
    }
}

pub trait ToRaqoteSource<'a> {
    fn to_raqote_source(self) -> Option<raqote::Source<'a>>;
}

impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle {
    fn to_raqote_source(self) -> Option<raqote::Source<'a>> {
        use canvas_traits::canvas::FillOrStrokeStyle::*;

        match self {
            Color(rgba) => Some(raqote::Source::Solid(raqote::SolidSource {
                r: rgba.red,
                g: rgba.green,
                b: rgba.blue,
                a: rgba.alpha,
            })),
            LinearGradient(_) => unimplemented!(),
            RadialGradient(_) => unimplemented!(),
            Surface(_) => unimplemented!(),
        }
    }
}

impl Color {
    fn as_raqote(&self) -> &raqote::SolidSource {
        match self {
            Color::Raqote(s) => s,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
use std::io::{File, Open, Write, TempDir};
use std::os::args;
use std::cast;
use std::raw::Slice;
use collections::priority_queue::PriorityQueue;
#[cfg(not(test))]
use std::from_str::from_str;
#[cfg(test)]
use std::io::{ReadWrite, SeekSet, EndOfFile};

/*
 * an entry is the number that we read and the file it came from, so after we took
 * out one Entry from the priority queue, we need to know where to take the next number
 * from.
 */
struct Entry {
	value: u64,
	source: File,
}

/* The priority queue depends on the ordering relation and always returns the biggest */
impl Ord for Entry {
	// lesser than implementation
	fn lt(&self, other: &Entry) -> bool {
		// we invert: for us the smallest will have the highest priority
		!(self.value < other.value)
	}
}

/* ordering needs equality for some reason, so there */
impl Eq for Entry {
	fn eq(&self, other: &Entry) -> bool {
		self.value == other.value
	}
}

/* A struct to hold our queue */
struct PriorityFile {
	queue: PriorityQueue<Entry>,
}

/*
 * 'Class' that takes a list of files and does a k-way merge of the smallest values
 * from the files
 */
impl PriorityFile {
	pub fn new(files: Vec<File>) -> PriorityFile {
		let mut queue: PriorityQueue<Entry> = PriorityQueue::new();
		// now that we got the queue, populate it with initial values

		// move_iter is required to get the values themselves, not borrowed pointers to them
		for mut f in files.move_iter() {
			// read from file, append to queue
			let number = match f.read_le_u64() {
				Ok(num) => num,
				Err(e) => fail!("failed to read u64 from file: {}", e),
			};
			queue.push(Entry {value: number, source: f});
		};
		PriorityFile {queue: queue}
	}

	/* Returns the next smallest number from the list of files or None if exhausted */
	pub fn next(&mut self) -> Option<u64> {
		match self.queue.maybe_pop() {
			Some(mut res) => {
				let v = res.value;
				match res.source.read_le_u64() {
					Ok(num) => self.queue.push(Entry {value: num, source: res.source}),
					Err(_) => (),
				};
				Some(v)
			},
			None => None,
		}
	}
}

fn read_u64(from: &mut File, n: uint) -> Vec<u64> {
	// rust post 0.10 will directly return a Vec<u8> here
	let buf = match from.read_exact(n*8) {
		Ok(b) => b,
		Err(e) => fail!("reading failed {}", e),
	};
	//let u = buf.as_ptr();
	let u = buf.as_slice();

	let mut r: Slice<u64> = unsafe { cast::transmute(u) };
	assert_eq!(r.len % 8, 0);
	r.len /= 8;
	Vec::from_slice(unsafe { cast::transmute(r) })
}

fn write_u64(to: &mut File, items: &Vec<u64>) {
	let s = items.as_slice();
	let mut r: Slice<u8> = unsafe { cast::transmute(s) };
	r.len *= 8;
	let buf: &[u8] = unsafe { cast::transmute(r) };

	match to.write(buf) {
		Ok(_) => (),
		Err(e) => fail!("writing failed: {}", e),
	};
}

fn externalSort(mut fdInput: File, size: u64, mut fdOutput: File, memSize: u64) {
	let mut runs = size / memSize;
	let items_per_run = (memSize / 8) as uint;
	let over = ((size / 8) - (items_per_run as u64 * runs)) as uint;

	info!("There will be {} runs with {} elements each.", runs, items_per_run);
	if over > 0 {
		info!("And one additional run with {} items.", over);
	}

	// let's create a temporary directory to store the sorted chunks
	// neat: TempDir deletes the directory and its contents when it goes out of
	// scope
	let overflow_dir = match TempDir::new("externalsort") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let overflow_path = overflow_dir.path();
	info!("temp dir:\ncd {}", overflow_path.display());

	// start the sorting runs
	for n in range(0, runs) {
		// iterate over our 'run' buffer and read from the input file
		// I suppose the values are little endian, which considering we are most
		// likely on x86, is a reasonable assumption
		info!("Run {}, starting read", n);
		let mut run = read_u64(&mut fdInput, items_per_run);
		info!("Run {}, read finished", n);
		// O(n log n) sort from the stdlib, hopefully more or less equivalent to
		// C++ std::sort
		info!("Run {}, starting sort", n);
		run.sort();
		info!("Run {}, sort finished", n);

		// now write out the results into numbered files
		let file_path = overflow_path.join(n.to_str());
		let mut file_file = match File::open_mode(&file_path, Open, Write) {
			Ok(f) => f,
			Err(e) => fail!("overflow file failed opening for write: {}", e),
		};

		info!("Run {}, starting write", n);
		write_u64(&mut file_file, &run);
		info!("Run {}, write finished", n);
	};

	/* additional run to catch remaining objects */
	if over > 0 {
		info!("overrun starting read");
		let mut run = read_u64(&mut fdInput, over);
		info!("overrun read finished");
		info!("overrun starting sort");
		run.sort();
		info!("overrun sort finished");

		let file_path = overflow_path.join(runs.to_str());
		let mut file_file = match File::open_mode(&file_path, Open, Write) {
			Ok(f) => f,
			Err(e) => fail!("overflow file failed opening for write: {}", e),
		};
		info!("overrun starting write");
		write_u64(&mut file_file, &run);
		info!("overrun finished write");

		runs += 1;
	};

	/* sorting done, now merging */
	info!("Pre-sorting done, now k-way merge")

	// collect all file handles. Hopefully less than 4096
	let mut files = Vec::with_capacity(runs as uint);
	for n in range(0, runs) {
		let file_path = overflow_path.join(n.to_str());
		let fd = match File::open(&file_path) {
			Ok(f) => f,
			Err(e) => fail!("overflow file opening error {}", e),
		};
		files.push(fd);
	}

	// we got a nice class here that spits out sorted numbers until exhausted
	let mut pf = PriorityFile::new(files);
	// put the sorted numbers in a cache first, so they can all be written in bulk
	let mut write_cache = Vec::with_capacity(items_per_run);
	loop {
		match pf.next() {
			Some (number) => {
				// a new number was found, add it to the cache
				// and if the cache is full, write that to disk
				write_cache.push(number);
				debug!("Gathered element {}", number);
				if write_cache.len() >= items_per_run {
					info!("Writing out {} elements from cache", write_cache.len());
					write_u64(&mut fdOutput, &write_cache);
					info!("Write done");
					write_cache.clear();
				};
			},
			None => {
				info!("Ending, writing out remaining {} elements from cache", write_cache.len());
				// we finished, write remaining cache to disk
				write_u64(&mut fdOutput, &write_cache);
				info!("Write done");
				break;
			},
		};
	};
}

#[cfg(not(test))]
fn main() {
	let argv = args();
	if argv.len() < 4 {
		fail!("Argument error: <inputFile> <outputFile> <memoryBufferInMB>");
	}
	let input_file_path = &Path::new(argv[1].clone());
	let size = match input_file_path.stat() {
		Ok(stat) => stat.size,
		Err(e) => fail!("Couldn't read {}", e),
	};
	let fin = match File::open(input_file_path) {
		Ok(f) => f,
		Err(e) => fail!("input file error: {}", e),
	};
	let fout = match File::open_mode(&Path::new(argv[2].clone()), Open, Write) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};
	let buffer_size:u64 = match from_str(args()[3].clone()) {
		Some(num) => num,
		None => fail!("Not numeric input"),
	};
	info!("Input file size {}", size);

	externalSort(fin, size, fout, buffer_size * 1024 * 1024);
}

#[test]
fn generate_5gb_and_sort() {
	let number_gigabytes = 1;

	let mut random = match File::open(&Path::new("/dev/urandom")) {
		Ok(f) => f,
		Err(e) => fail!("Error opening urandom: {}", e),
	};

	let test_dir = match TempDir::new("externalsort-test") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let test_path = test_dir.path();

	let mut unordered_nums = match File::open_mode(&test_path.join("input"), Open, ReadWrite) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	let mut buffer = [0, .. 1024*1024];
	let mut left = number_gigabytes * 1024;
	while left > 0 {
		match random.read(buffer) {
			Ok(_) => match unordered_nums.write(buffer) {
				Ok(_) => (),
				Err(e) => fail!("failed writing random numbers {}", e),
			},
			Err(e) => fail!("failed reading random numbers {}", e),
		};
		left -= 1;
	}

	match unordered_nums.seek(0, SeekSet) {
		Ok(_) => (),
		Err(e) => fail!("Failed to seek: {}", e),
	};

	let ordered_nums = match File::open_mode(&test_path.join("output"), Open, Write) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	externalSort(unordered_nums, 1024 * 1024 * 1024 * number_gigabytes, ordered_nums, 1024 * 1024 * 100);
	let mut ordered_nums = match File::open(&test_path.join("output")) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	let mut last = 0_u64;
	loop {
		let number = match ordered_nums.read_le_u64() {
			Ok(num) => num,
			Err(e) => {
				match e.kind {
					EndOfFile => break,
					_ => fail!("Error reading from file: {}", e),
				}
			}
		};
		assert!(number >= last);
		last = number;
	}
}
<commit_msg>Don't clone without need<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
use std::io::{File, Open, Write, TempDir};
use std::os::args;
use std::cast;
use std::raw::Slice;
use collections::priority_queue::PriorityQueue;
#[cfg(not(test))]
use std::from_str::from_str;
#[cfg(test)]
use std::io::{ReadWrite, SeekSet, EndOfFile};

/*
 * an entry is the number that we read and the file it came from, so after we took
 * out one Entry from the priority queue, we need to know where to take the next number
 * from.
 */
struct Entry {
	value: u64,
	source: File,
}

/* The priority queue depends on the ordering relation and always returns the biggest */
impl Ord for Entry {
	// lesser than implementation
	fn lt(&self, other: &Entry) -> bool {
		// we invert: for us the smallest will have the highest priority
		!(self.value < other.value)
	}
}

/* ordering needs equality for some reason, so there */
impl Eq for Entry {
	fn eq(&self, other: &Entry) -> bool {
		self.value == other.value
	}
}

/* A struct to hold our queue */
struct PriorityFile {
	queue: PriorityQueue<Entry>,
}

/*
 * 'Class' that takes a list of files and does a k-way merge of the smallest values
 * from the files
 */
impl PriorityFile {
	pub fn new(files: Vec<File>) -> PriorityFile {
		let mut queue: PriorityQueue<Entry> = PriorityQueue::new();
		// now that we got the queue, populate it with initial values

		// move_iter is required to get the values themselves, not borrowed pointers to them
		for mut f in files.move_iter() {
			// read from file, append to queue
			let number = match f.read_le_u64() {
				Ok(num) => num,
				Err(e) => fail!("failed to read u64 from file: {}", e),
			};
			queue.push(Entry {value: number, source: f});
		};
		PriorityFile {queue: queue}
	}

	/* Returns the next smallest number from the list of files or None if exhausted */
	pub fn next(&mut self) -> Option<u64> {
		match self.queue.maybe_pop() {
			Some(mut res) => {
				let v = res.value;
				match res.source.read_le_u64() {
					Ok(num) => self.queue.push(Entry {value: num, source: res.source}),
					Err(_) => (),
				};
				Some(v)
			},
			None => None,
		}
	}
}

fn read_u64(from: &mut File, n: uint) -> Vec<u64> {
	// rust post 0.10 will directly return a Vec<u8> here
	let buf = match from.read_exact(n*8) {
		Ok(b) => b,
		Err(e) => fail!("reading failed {}", e),
	};
	//let u = buf.as_ptr();
	let u = buf.as_slice();

	let mut r: Slice<u64> = unsafe { cast::transmute(u) };
	assert_eq!(r.len % 8, 0);
	r.len /= 8;
	Vec::from_slice(unsafe { cast::transmute(r) })
}

fn write_u64(to: &mut File, items: &Vec<u64>) {
	let s = items.as_slice();
	let mut r: Slice<u8> = unsafe { cast::transmute(s) };
	r.len *= 8;
	let buf: &[u8] = unsafe { cast::transmute(r) };

	match to.write(buf) {
		Ok(_) => (),
		Err(e) => fail!("writing failed: {}", e),
	};
}

fn externalSort(mut fdInput: File, size: u64, mut fdOutput: File, memSize: u64) {
	let mut runs = size / memSize;
	let items_per_run = (memSize / 8) as uint;
	let over = ((size / 8) - (items_per_run as u64 * runs)) as uint;

	info!("There will be {} runs with {} elements each.", runs, items_per_run);
	if over > 0 {
		info!("And one additional run with {} items.", over);
	}

	// let's create a temporary directory to store the sorted chunks
	// neat: TempDir deletes the directory and its contents when it goes out of
	// scope
	let overflow_dir = match TempDir::new("externalsort") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let overflow_path = overflow_dir.path();
	info!("temp dir:\ncd {}", overflow_path.display());

	// start the sorting runs
	for n in range(0, runs) {
		// iterate over our 'run' buffer and read from the input file
		// I suppose the values are little endian, which considering we are most
		// likely on x86, is a reasonable assumption
		info!("Run {}, starting read", n);
		let mut run = read_u64(&mut fdInput, items_per_run);
		info!("Run {}, read finished", n);
		// O(n log n) sort from the stdlib, hopefully more or less equivalent to
		// C++ std::sort
		info!("Run {}, starting sort", n);
		run.sort();
		info!("Run {}, sort finished", n);

		// now write out the results into numbered files
		let file_path = overflow_path.join(n.to_str());
		let mut file_file = match File::open_mode(&file_path, Open, Write) {
			Ok(f) => f,
			Err(e) => fail!("overflow file failed opening for write: {}", e),
		};

		info!("Run {}, starting write", n);
		write_u64(&mut file_file, &run);
		info!("Run {}, write finished", n);
	};

	/* additional run to catch remaining objects */
	if over > 0 {
		info!("overrun starting read");
		let mut run = read_u64(&mut fdInput, over);
		info!("overrun read finished");
		info!("overrun starting sort");
		run.sort();
		info!("overrun sort finished");

		let file_path = overflow_path.join(runs.to_str());
		let mut file_file = match File::open_mode(&file_path, Open, Write) {
			Ok(f) => f,
			Err(e) => fail!("overflow file failed opening for write: {}", e),
		};
		info!("overrun starting write");
		write_u64(&mut file_file, &run);
		info!("overrun finished write");

		runs += 1;
	};

	/* sorting done, now merging */
	info!("Pre-sorting done, now k-way merge")

	// collect all file handles. Hopefully less than 4096
	let mut files = Vec::with_capacity(runs as uint);
	for n in range(0, runs) {
		let file_path = overflow_path.join(n.to_str());
		let fd = match File::open(&file_path) {
			Ok(f) => f,
			Err(e) => fail!("overflow file opening error {}", e),
		};
		files.push(fd);
	}

	// we got a nice class here that spits out sorted numbers until exhausted
	let mut pf = PriorityFile::new(files);
	// put the sorted numbers in a cache first, so they can all be written in bulk
	let mut write_cache = Vec::with_capacity(items_per_run);
	loop {
		match pf.next() {
			Some (number) => {
				// a new number was found, add it to the cache
				// and if the cache is full, write that to disk
				write_cache.push(number);
				debug!("Gathered element {}", number);
				if write_cache.len() >= items_per_run {
					info!("Writing out {} elements from cache", write_cache.len());
					write_u64(&mut fdOutput, &write_cache);
					info!("Write done");
					write_cache.clear();
				};
			},
			None => {
				info!("Ending, writing out remaining {} elements from cache", write_cache.len());
				// we finished, write remaining cache to disk
				write_u64(&mut fdOutput, &write_cache);
				info!("Write done");
				break;
			},
		};
	};
}

#[cfg(not(test))]
fn main() {
	let argv = args();
	if argv.len() < 4 {
		fail!("Argument error: <inputFile> <outputFile> <memoryBufferInMB>");
	}
	let input_file_path = &Path::new(argv[1].as_slice());
	let size = match input_file_path.stat() {
		Ok(stat) => stat.size,
		Err(e) => fail!("Couldn't read {}", e),
	};
	let fin = match File::open(input_file_path) {
		Ok(f) => f,
		Err(e) => fail!("input file error: {}", e),
	};
	let fout = match File::open_mode(&Path::new(argv[2].as_slice()), Open, Write) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};
	let buffer_size:u64 = match from_str(args()[3].as_slice()) {
		Some(num) => num,
		None => fail!("Not numeric input"),
	};
	info!("Input file size {}", size);

	externalSort(fin, size, fout, buffer_size * 1024 * 1024);
}

#[test]
fn generate_5gb_and_sort() {
	let number_gigabytes = 1;

	let mut random = match File::open(&Path::new("/dev/urandom")) {
		Ok(f) => f,
		Err(e) => fail!("Error opening urandom: {}", e),
	};

	let test_dir = match TempDir::new("externalsort-test") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let test_path = test_dir.path();

	let mut unordered_nums = match File::open_mode(&test_path.join("input"), Open, ReadWrite) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	let mut buffer = [0, .. 1024*1024];
	let mut left = number_gigabytes * 1024;
	while left > 0 {
		match random.read(buffer) {
			Ok(_) => match unordered_nums.write(buffer) {
				Ok(_) => (),
				Err(e) => fail!("failed writing random numbers {}", e),
			},
			Err(e) => fail!("failed reading random numbers {}", e),
		};
		left -= 1;
	}

	match unordered_nums.seek(0, SeekSet) {
		Ok(_) => (),
		Err(e) => fail!("Failed to seek: {}", e),
	};

	let ordered_nums = match File::open_mode(&test_path.join("output"), Open, Write) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	externalSort(unordered_nums, 1024 * 1024 * 1024 * number_gigabytes, ordered_nums, 1024 * 1024 * 100);
	let mut ordered_nums = match File::open(&test_path.join("output")) {
		Ok(f) => f,
		Err(e) => fail!("output file error: {}", e),
	};

	let mut last = 0_u64;
	loop {
		let number = match ordered_nums.read_le_u64() {
			Ok(num) => num,
			Err(e) => {
				match e.kind {
					EndOfFile => break,
					_ => fail!("Error reading from file: {}", e),
				}
			}
		};
		assert!(number >= last);
		last = number;
	}
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    str::FromStr,
    sync::Arc,
    time::Instant,
};

use ra_db::{
    salsa::{Database, Durability},
    FileId, SourceDatabaseExt,
};
use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};

use crate::Result;

pub(crate) struct Position {
    path: PathBuf,
    line: u32,
    column: u32,
}

impl FromStr for Position {
    type Err = Box<dyn std::error::Error + Send + Sync>;
    fn from_str(s: &str) -> Result<Self> {
        let (path_line, column) = rsplit_at_char(s, ':')?;
        let (path, line) = rsplit_at_char(path_line, ':')?;
        Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? })
    }
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}

pub(crate) enum Op {
    Highlight { path: PathBuf },
    Complete(Position),
    GotoDef(Position),
}

pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
    ra_prof::init();

    let start = Instant::now();
    eprint!("loading: ");
    let (mut host, roots) = ra_batch::load_cargo(path)?;
    let db = host.raw_database();
    eprintln!("{:?}\n", start.elapsed());

    let file_id = {
        let path = match &op {
            Op::Highlight { path } => path,
            Op::Complete(pos) | Op::GotoDef(pos) => &pos.path,
        };
        let path = std::env::current_dir()?.join(path).canonicalize()?;
        roots
            .iter()
            .find_map(|(source_root_id, project_root)| {
                if project_root.is_member() {
                    for file_id in db.source_root(*source_root_id).walk() {
                        let rel_path = db.file_relative_path(file_id);
                        let abs_path = rel_path.to_path(project_root.path());
                        if abs_path == path {
                            return Some(file_id);
                        }
                    }
                }
                None
            })
            .ok_or_else(|| format!("Can't find {:?}", path))?
    };

    match &op {
        Op::Highlight { .. } => {
            let res = do_work(&mut host, file_id, |analysis| {
                analysis.diagnostics(file_id).unwrap();
                analysis.highlight_as_html(file_id, false).unwrap()
            });
            if verbose {
                println!("\n{}", res);
            }
        }
        Op::Complete(pos) | Op::GotoDef(pos) => {
            let is_completion = match op {
                Op::Complete(..) => true,
                _ => false,
            };

            let offset = host
                .analysis()
                .file_line_index(file_id)?
                .offset(LineCol { line: pos.line, col_utf16: pos.column });
            let file_postion = FilePosition { file_id, offset };

            if is_completion {
                let res =
                    do_work(&mut host, file_id, |analysis| analysis.completions(file_postion));
                if verbose {
                    println!("\n{:#?}", res);
                }
            } else {
                let res =
                    do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion));
                if verbose {
                    println!("\n{:#?}", res);
                }
            }
        }
    }
    Ok(())
}

fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T {
    {
        let start = Instant::now();
        eprint!("from scratch:   ");
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("no change:      ");
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("trivial change: ");
        host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW);
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("comment change: ");
        {
            let mut text = host.analysis().file_text(file_id).unwrap().to_string();
            text.push_str("\n/* Hello world */\n");
            let mut change = AnalysisChange::new();
            change.change_file(file_id, Arc::new(text));
            host.apply_change(change);
        }
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("const change:   ");
        host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH);
        let res = work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
        res
    }
}
<commit_msg>1-based columns<commit_after>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    str::FromStr,
    sync::Arc,
    time::Instant,
};

use ra_db::{
    salsa::{Database, Durability},
    FileId, SourceDatabaseExt,
};
use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};

use crate::Result;

pub(crate) struct Position {
    path: PathBuf,
    line: u32,
    column: u32,
}

impl FromStr for Position {
    type Err = Box<dyn std::error::Error + Send + Sync>;
    fn from_str(s: &str) -> Result<Self> {
        let (path_line, column) = rsplit_at_char(s, ':')?;
        let (path, line) = rsplit_at_char(path_line, ':')?;
        Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? })
    }
}

fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
    let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
    Ok((&s[..idx], &s[idx + 1..]))
}

pub(crate) enum Op {
    Highlight { path: PathBuf },
    Complete(Position),
    GotoDef(Position),
}

pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
    ra_prof::init();

    let start = Instant::now();
    eprint!("loading: ");
    let (mut host, roots) = ra_batch::load_cargo(path)?;
    let db = host.raw_database();
    eprintln!("{:?}\n", start.elapsed());

    let file_id = {
        let path = match &op {
            Op::Highlight { path } => path,
            Op::Complete(pos) | Op::GotoDef(pos) => &pos.path,
        };
        let path = std::env::current_dir()?.join(path).canonicalize()?;
        roots
            .iter()
            .find_map(|(source_root_id, project_root)| {
                if project_root.is_member() {
                    for file_id in db.source_root(*source_root_id).walk() {
                        let rel_path = db.file_relative_path(file_id);
                        let abs_path = rel_path.to_path(project_root.path());
                        if abs_path == path {
                            return Some(file_id);
                        }
                    }
                }
                None
            })
            .ok_or_else(|| format!("Can't find {:?}", path))?
    };

    match &op {
        Op::Highlight { .. } => {
            let res = do_work(&mut host, file_id, |analysis| {
                analysis.diagnostics(file_id).unwrap();
                analysis.highlight_as_html(file_id, false).unwrap()
            });
            if verbose {
                println!("\n{}", res);
            }
        }
        Op::Complete(pos) | Op::GotoDef(pos) => {
            let is_completion = match op {
                Op::Complete(..) => true,
                _ => false,
            };

            let offset = host
                .analysis()
                .file_line_index(file_id)?
                .offset(LineCol { line: pos.line - 1, col_utf16: pos.column });
            let file_postion = FilePosition { file_id, offset };

            if is_completion {
                let res =
                    do_work(&mut host, file_id, |analysis| analysis.completions(file_postion));
                if verbose {
                    println!("\n{:#?}", res);
                }
            } else {
                let res =
                    do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion));
                if verbose {
                    println!("\n{:#?}", res);
                }
            }
        }
    }
    Ok(())
}

fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T {
    {
        let start = Instant::now();
        eprint!("from scratch:   ");
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("no change:      ");
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("trivial change: ");
        host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW);
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("comment change: ");
        {
            let mut text = host.analysis().file_text(file_id).unwrap().to_string();
            text.push_str("\n/* Hello world */\n");
            let mut change = AnalysisChange::new();
            change.change_file(file_id, Arc::new(text));
            host.apply_change(change);
        }
        work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
    }
    {
        let start = Instant::now();
        eprint!("const change:   ");
        host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH);
        let res = work(&host.analysis());
        eprintln!("{:?}", start.elapsed());
        res
    }
}
<|endoftext|>


<commit_before>//! RA Proc Macro Server
//!
//! This library is able to call compiled Rust custom derive dynamic libraries on arbitrary code.
//! The general idea here is based on https://github.com/fedochet/rust-proc-macro-expander.
//!
//! But we change some several design for fitting RA needs:
//!
//! * We use `ra_tt` for proc-macro `TokenStream` server, it is easy to manipute and interact with
//!   RA then proc-macro2 token stream.
//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable`
//!   rustc rather than `unstable`. (Although in gerenal ABI compatibility is still an issue)

#[allow(dead_code)]
#[doc(hidden)]
mod proc_macro;

use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};

pub fn expand_task(_task: &ExpansionTask) -> Result<ExpansionResult, String> {
    unimplemented!()
}

pub fn list_macros(_task: &ListMacrosTask) -> Result<ListMacrosResult, String> {
    unimplemented!()
}
<commit_msg>Add bridge::TokenStream to crate scope<commit_after>//! RA Proc Macro Server
//!
//! This library is able to call compiled Rust custom derive dynamic libraries on arbitrary code.
//! The general idea here is based on https://github.com/fedochet/rust-proc-macro-expander.
//!
//! But we change some several design for fitting RA needs:
//!
//! * We use `ra_tt` for proc-macro `TokenStream` server, it is easy to manipute and interact with
//!   RA then proc-macro2 token stream.
//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable`
//!   rustc rather than `unstable`. (Although in gerenal ABI compatibility is still an issue)

#[allow(dead_code)]
#[doc(hidden)]
mod proc_macro;

use proc_macro::bridge::client::TokenStream;
use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};

pub fn expand_task(_task: &ExpansionTask) -> Result<ExpansionResult, String> {
    unimplemented!()
}

pub fn list_macros(_task: &ListMacrosTask) -> Result<ListMacrosResult, String> {
    unimplemented!()
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nickel;
extern crate hyper;
extern crate rustc_serialize;

use nickel::{Nickel, ListeningServer, HttpRouter, JsonBody};
use nickel::status::StatusCode;

use rustc_serialize::json::Json;

use std::error::Error as StdError;
use std::{env, str};
use std::sync::atomic::{self, AtomicUsize};

fn main() {
    let port = env::var("PORT").map(|s| s.parse().unwrap()).unwrap_or(3000);

    start_server(&format!("0.0.0.0:{}", port)).unwrap();
}

fn start_server(address: &str) -> Result<ListeningServer, Box<StdError>> {
    let hits = AtomicUsize::new(0);
    let mut server = Nickel::with_data(hits);

    // Track all hits to the server
    server.utilize(middleware! { |_req, res| <AtomicUsize>
        let _hits = res.data().fetch_add(1, atomic::Ordering::Relaxed);
        return res.next_middleware()
    });

    // Core server
    server.get("/", middleware!( "Hello World" ));

    // Json example
    server.post("/", middleware! { |req, res|
        #[derive(RustcEncodable, RustcDecodable)]
        struct Data { name: String, age: Option<u32> }

        let client = try_with!(res, req.json_as::<Data>().map_err(|e| (StatusCode::BadRequest, e)));

        match client.age {
            Some(age) => {
                Json::from_str(&format!(
                    r#"{{ "message": "Hello {}, your age is {}" }}"#,
                    client.name,
                    age
                )).unwrap()
            }
            None => {
                Json::from_str(&format!(
                    r#"{{ "message": "Hello {}, I don't know your age" }}"#,
                    client.name
                )).unwrap()
            }
        }
    });

    // Get the hitcount
    server.get("/hits", middleware!{ |_req, res| <AtomicUsize>
        let hits = res.data().load(atomic::Ordering::Relaxed);

        hits.to_string()
    });

    server.listen(address)
}

#[cfg(test)]
mod tests {
    use self::support::{Body, Server, STATIC_SERVER, get, post};

    use hyper::header;
    use nickel::status::StatusCode;
    use rustc_serialize::json::Json;

    use std::{thread, time};

    fn get_hits_after_delay(server: &Server) -> u32 {
        // let other tests hit the server
        thread::sleep(time::Duration::from_secs(1));

        let mut response = server.get("/hits");
        response.body().parse().unwrap()
    }

    #[test]
    fn root_responds_with_hello_world() {
        let mut response = get("/");

        assert_eq!(response.body(), "Hello World");
        assert_eq!(response.status, StatusCode::Ok);
    }

    #[test]
    // FIXME: This will probably fail if tests are run without parallelism
    fn server_is_shared_with_other_tests() {
        assert!(get_hits_after_delay(&STATIC_SERVER) > 1);
    }

    #[test]
    fn root_responds_with_modified_json() {
        let mut response = post("/", r#"{ "name": "Rust", "age": 1 }"#);

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["message"].as_string(), Some("Hello Rust, your age is 1"));
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    #[test]
    fn accepts_json_with_missing_fields() {
        let mut response = post("/", r#"{ "name": "Rust" }"#);

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["message"].as_string(), Some("Hello Rust, I don't know your age"));
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    #[test]
    fn doesnt_accept_bad_inputs() {
        let response = post("/", r#"{ }"#);
        assert_eq!(response.status, StatusCode::BadRequest);
    }

    /// This test has a Server instance all to itself.
    #[test]
    fn non_shared_server() {
        let test_local_server = {
            let server = super::start_server("127.0.0.1:0").unwrap();
            Server::new(server)
        };

        assert_eq!(get_hits_after_delay(&test_local_server), 1);
    }

    mod support {
        use hyper::client::{Client, Response as HyperResponse};
        use nickel::ListeningServer;

        use std::net::SocketAddr;

        pub trait Body {
            fn body(self) -> String;
        }

        impl<'a> Body for &'a mut HyperResponse {
            fn body(self) -> String {
                use std::io::Read;
                let mut body = String::new();
                self.read_to_string(&mut body).expect("Failed to read body of Response");
                println!("Read body: {}", body);
                body
            }
        }

        /// An example wrapper type to make testing more readable
        pub struct Server(SocketAddr);
        impl Server {
            pub fn new(server: ListeningServer) -> Server {
                let wrapped = Server(server.socket());

                // detaching is important otherwise it would block the test threads.
                server.detach();

                wrapped
            }

            pub fn get(&self, path: &str) -> HyperResponse {
                let url = self.url_for(path);
                Client::new().get(&url).send().unwrap()
            }

            pub fn post(&self, path: &str, body: &str) -> HyperResponse {
                let url = self.url_for(path);
                Client::new().post(&url).body(body).send().unwrap()
            }

            pub fn url_for(&self, path: &str) -> String {
                format!("http://{}{}", self.0, path)
            }
        }

        lazy_static! {
            /// This is a shared instance of the server between all the tests
            pub static ref STATIC_SERVER: Server = {
                let server = super::super::start_server("127.0.0.1:0").unwrap();
                Server::new(server)
            };
        }

        /// Example of a free function version of `get` which uses the shared server
        pub fn get(path: &str) -> HyperResponse {
            STATIC_SERVER.get(path)
        }

        /// Example of a free function version of `post` which uses the shared server
        pub fn post(path: &str, body: &str) -> HyperResponse {
            STATIC_SERVER.post(path, body)
        }
    }
}
<commit_msg>doc(examples): flesh out the integration test example with a dummy database<commit_after>#[macro_use]
extern crate nickel;
extern crate hyper;
extern crate rustc_serialize;

use nickel::{Nickel, ListeningServer, HttpRouter, JsonBody};
use nickel::status::StatusCode;

use rustc_serialize::json::Json;

use std::error::Error as StdError;
use std::{env, str};
use std::sync::atomic::{self, AtomicUsize};

// Example trait to allow custom databases to be used within the integration tests
// to test different behaviours without touching a real database.
trait Database : Send + Sync + 'static {
    fn get_users(&self) -> Vec<String>;
}

impl Database for Vec<String> {
    fn get_users(&self) -> Vec<String> {
        self.clone()
    }
}

struct ServerData {
    hits: AtomicUsize,

    // FIXME: The `middleware` macro typehinting doesn't support hinting with
    // typeparams, i.e. the hint can't be `< ServerData<T> >` where T is a
    // typeparam from the enclosing function, e.g. `start_server`.
    //
    // To counter this limitation, we've boxed the trait so that specifying the
    // typeparam is unnecessary.
    database: Box<Database>
}

impl ServerData {
    fn hitcount(&self) -> usize {
        self.hits.load(atomic::Ordering::Relaxed)
    }

    fn log_hit(&self) -> usize {
        self.hits.fetch_add(1, atomic::Ordering::Relaxed)
    }

    fn get_users(&self) -> Vec<String> {
        self.database.get_users()
    }
}

fn main() {
    let port = env::var("PORT").map(|s| s.parse().unwrap()).unwrap_or(3000);
    let address = &format!("0.0.0.0:{}", port);
    let database = vec![];

    start_server(address, database).unwrap();
}

fn start_server<D>(address: &str, database: D) -> Result<ListeningServer, Box<StdError>>
where D: Database {
    let server_data = ServerData {
        hits: AtomicUsize::new(0),
        database: Box::new(database),
    };

    let mut server = Nickel::with_data(server_data);

    // Track all hits to the server
    server.utilize(middleware! { |_req, res| <ServerData>
        res.data().log_hit();
        return res.next_middleware()
    });

    // Core server
    server.get("/", middleware!( "Hello World" ));

    server.get("/users", middleware! { |_, res| <ServerData>
        let users = res.data().get_users();

        Json::from_str(&format!(r#"{{ "users": {:?} }}"#, users)).unwrap()
    });

    // Json example
    server.post("/", middleware! { |req, res|
        #[derive(RustcEncodable, RustcDecodable)]
        struct Data { name: String, age: Option<u32> }

        let client = try_with!(res, req.json_as::<Data>().map_err(|e| (StatusCode::BadRequest, e)));

        match client.age {
            Some(age) => {
                Json::from_str(&format!(
                    r#"{{ "message": "Hello {}, your age is {}" }}"#,
                    client.name,
                    age
                )).unwrap()
            }
            None => {
                Json::from_str(&format!(
                    r#"{{ "message": "Hello {}, I don't know your age" }}"#,
                    client.name
                )).unwrap()
            }
        }
    });

    // Get the hitcount
    server.get("/hits", middleware!{ |_req, res| <ServerData>
        res.data().hitcount().to_string()
    });

    server.listen(address)
}

#[cfg(test)]
mod tests {
    use self::support::{Body, Server, STATIC_SERVER, get, post};

    use hyper::header;
    use nickel::status::StatusCode;
    use rustc_serialize::json::Json;

    use std::{thread, time};

    fn get_hits_after_delay(server: &Server) -> u32 {
        // let other tests hit the server
        thread::sleep(time::Duration::from_secs(1));

        let mut response = server.get("/hits");
        response.body().parse().unwrap()
    }

    #[test]
    fn root_responds_with_hello_world() {
        let mut response = get("/");

        assert_eq!(response.body(), "Hello World");
        assert_eq!(response.status, StatusCode::Ok);
    }

    #[test]
    // FIXME: This will probably fail if tests are run without parallelism
    fn server_is_shared_with_other_tests() {
        assert!(get_hits_after_delay(&STATIC_SERVER) > 1);
    }

    #[test]
    fn root_responds_with_modified_json() {
        let mut response = post("/", r#"{ "name": "Rust", "age": 1 }"#);

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["message"].as_string(), Some("Hello Rust, your age is 1"));
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    #[test]
    fn accepts_json_with_missing_fields() {
        let mut response = post("/", r#"{ "name": "Rust" }"#);

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["message"].as_string(), Some("Hello Rust, I don't know your age"));
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    #[test]
    fn doesnt_accept_bad_inputs() {
        let response = post("/", r#"{ }"#);
        assert_eq!(response.status, StatusCode::BadRequest);
    }

    /// This test has a Server instance all to itself.
    #[test]
    fn non_shared_server() {
        let test_local_server = {
            let server = super::start_server("127.0.0.1:0", vec![]).unwrap();
            Server::new(server)
        };

        assert_eq!(get_hits_after_delay(&test_local_server), 1);
    }

    #[test]
    fn has_no_users_by_default() {
        let mut response = get("/users");

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["users"].as_array().unwrap().len(), 0);
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    #[test]
    fn non_shared_server_with_different_database() {
        let server = {
            let bots = vec!["bors".into(), "homu".into(), "highfive".into()];
            let server = super::start_server("127.0.0.1:0", bots).unwrap();
            Server::new(server)
        };

        let mut response = server.get("/users");

        let json = Json::from_str(&response.body()).unwrap();

        assert_eq!(json["users"].as_array().unwrap().len(), 3);
        assert_eq!(response.status, StatusCode::Ok);
        assert_eq!(
            response.headers.get::<header::ContentType>(),
            Some(&header::ContentType::json())
        );
    }

    mod support {
        use hyper::client::{Client, Response as HyperResponse};
        use nickel::ListeningServer;

        use std::net::SocketAddr;

        pub trait Body {
            fn body(self) -> String;
        }

        impl<'a> Body for &'a mut HyperResponse {
            fn body(self) -> String {
                use std::io::Read;
                let mut body = String::new();
                self.read_to_string(&mut body).expect("Failed to read body of Response");
                println!("Read body: {}", body);
                body
            }
        }

        /// An example wrapper type to make testing more readable
        pub struct Server(SocketAddr);
        impl Server {
            pub fn new(server: ListeningServer) -> Server {
                let wrapped = Server(server.socket());

                // detaching is important otherwise it would block the test threads.
                server.detach();

                wrapped
            }

            pub fn get(&self, path: &str) -> HyperResponse {
                let url = self.url_for(path);
                Client::new().get(&url).send().unwrap()
            }

            pub fn post(&self, path: &str, body: &str) -> HyperResponse {
                let url = self.url_for(path);
                Client::new().post(&url).body(body).send().unwrap()
            }

            pub fn url_for(&self, path: &str) -> String {
                format!("http://{}{}", self.0, path)
            }
        }

        lazy_static! {
            /// This is a shared instance of the server between all the tests
            pub static ref STATIC_SERVER: Server = {
                let server = super::super::start_server("127.0.0.1:0", vec![]).unwrap();
                Server::new(server)
            };
        }

        /// Example of a free function version of `get` which uses the shared server
        pub fn get(path: &str) -> HyperResponse {
            STATIC_SERVER.get(path)
        }

        /// Example of a free function version of `post` which uses the shared server
        pub fn post(path: &str, body: &str) -> HyperResponse {
            STATIC_SERVER.post(path, body)
        }
    }
}
<|endoftext|>


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

use ast;
use ast::*;

impl ast::ComponentValue {
    pub fn to_css(&mut self) -> ~str {
        let mut css = ~"";
        self.to_css_push(&mut css);
        css
    }

    pub fn to_css_push(&self, css: &mut ~str) {
        match *self {
            Ident(ref value) => serialize_identifier(value.as_slice(), css),
            AtKeyword(ref value) => {
                css.push_char('@');
                serialize_identifier(value.as_slice(), css);
            },
            Hash(ref value) | IDHash(ref value) => {
                css.push_char('#');
                serialize_identifier(value.as_slice(), css);
            }
            String(ref value) => serialize_string(value.as_slice(), css),
            URL(ref value) => {
                css.push_str("url(");
                serialize_string(value.as_slice(), css);
                css.push_char(')');
            },
            Delim(value) => css.push_char(value),

            Number(ref value) => css.push_str(value.representation),
            Percentage(ref value) => {
                css.push_str(value.representation);
                css.push_char('%');
            },
            Dimension(ref value, ref unit) => {
                css.push_str(value.representation);
                serialize_identifier(unit.as_slice(), css);
            },

            UnicodeRange(start, end) => {
                css.push_str(format!("U+{:X}", start));
                if end != start {
                    css.push_str(format!("-{:X}", end));
                }
            }

            WhiteSpace => css.push_char(' '),
            Colon => css.push_char(':'),
            Semicolon => css.push_char(';'),
            Comma => css.push_char(','),
            IncludeMatch => css.push_str("~="),
            DashMatch => css.push_str("|="),
            PrefixMatch => css.push_str("^="),
            SuffixMatch => css.push_str("$="),
            SubstringMatch => css.push_str("*="),
            Column => css.push_str("||"),
            CDO => css.push_str("<!--"),
            CDC => css.push_str("-->"),

            Function(ref name, ref arguments) => {
                serialize_identifier(name.as_slice(), css);
                css.push_char('(');
                arguments.iter().to_css_push(css);
                css.push_char(')');
            },
            ParenthesisBlock(ref content) => {
                css.push_char('(');
                content.iter().to_css_push(css);
                css.push_char(')');
            },
            SquareBracketBlock(ref content) => {
                css.push_char('[');
                content.iter().to_css_push(css);
                css.push_char(']');
            },
            CurlyBracketBlock(ref content) => {
                css.push_char('{');
                content.iter().map(|t| match *t { (ref c, _) => c }).to_css_push(css);
                css.push_char('}');
            },

            BadURL => css.push_str("url(<bad url>)"),
            BadString => css.push_str("\"<bad string>\n"),
            CloseParenthesis => css.push_char(')'),
            CloseSquareBracket => css.push_char(']'),
            CloseCurlyBracket => css.push_char('}'),
        }
    }
}

pub fn serialize_identifier(value: &str, css: &mut ~str) {
    // TODO: avoid decoding/re-encoding UTF-8?
    let mut iter = value.iter();
    let mut c = iter.next().unwrap();
    if c == '-' {
        c = match iter.next() {
            None => {
                css.push_str("\\-");
                return
            }
            Some(c) => {
                css.push_char('-');
                c
            },
        }
    };
    match c {
        'A'..'Z' | 'a'..'z' | '_' => css.push_char(c),
        _ if c > '\x7F' => css.push_char(c),
        '\n' => css.push_str("\\A "),
        '\r' => css.push_str("\\D "),
        '\x0C' => css.push_str("\\C "),
        '0'..'9' => css.push_str(format!("\\\\3{} ", c)),
        _ => { css.push_char('\\'); css.push_char(c) },
    }
    for c in iter {
        match c {
            '0'..'9' | 'A'..'Z' | 'a'..'z' | '_' | '-' => css.push_char(c),
            _ if c > '\x7F' => css.push_char(c),
            '\n' => css.push_str("\\A "),
            '\r' => css.push_str("\\D "),
            '\x0C' => css.push_str("\\C "),
            _ => { css.push_char('\\'); css.push_char(c) },
        }
    }
}

pub fn serialize_string(value: &str, css: &mut ~str) {
    css.push_char('"');
    // TODO: avoid decoding/re-encoding UTF-8?
    for c in value.iter() {
        match c {
            '"' => css.push_str("\""),
            '\\' => css.push_str("\\\\"),
            '\n' => css.push_str("\\A "),
            '\r' => css.push_str("\\D "),
            '\x0C' => css.push_str("\\C "),
            _ => css.push_char(c),
        }
    }
    css.push_char('"');
}

pub trait ToCss {
    fn to_css(&mut self) -> ~str {
        let mut css = ~"";
        self.to_css_push(&mut css);
        css
    }

    fn to_css_push(&mut self, css: &mut ~str);
}

impl<'self, I: Iterator<&'self ComponentValue>> ToCss for I {
    fn to_css_push(&mut self, css: &mut ~str) {
        let mut previous = match self.next() {
            None => return,
            Some(first) => { first.to_css_push(css); first }
        };
        macro_rules! matches(
            ($value:expr, $($pattern:pat)|+) => (
                match $value { $($pattern)|+ => true, _ => false }
            );
        )
        loop { match self.next() { None => break, Some(component_value) => {
            let (a, b) = (previous, component_value);
            if (
                matches!(*a, Hash(*) | IDHash(*) | AtKeyword(*)) &&
                matches!(*b, Number(*) | Percentage(*) | Ident(*) | Dimension(*) |
                            UnicodeRange(*) | URL(*) | Function(*))
            ) || (
                matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
                matches!(*b, Number(*) | Ident(*) | Dimension(*))
            ) || (
                matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
                matches!(*b, Percentage(*) | UnicodeRange(*) | URL(*) | Function(*))
            ) || (
                matches!(*a, Ident(*)) &&
                matches!(*b, ParenthesisBlock(*))
            ) || (
                matches!(*a, Delim('#') | Delim('@')) &&
                !matches!(*b, WhiteSpace)
            ) || (
                matches!(*a, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
                             Delim('>') | Delim('!')) &&
                !matches!(*b, WhiteSpace)
            ) || (
                !matches!(*a, WhiteSpace) &&
                matches!(*b, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
                             Delim('>') | Delim('!'))
            ) || (
                matches!(*a, Delim('/')) &&
                matches!(*b, Delim('*'))
            ) || (
                matches!(*a, Delim('*')) &&
                matches!(*b, Delim('/'))
            ) {
                css.push_str("/**/")
            }
            component_value.to_css_push(css);
            previous = component_value;
        }}}
    }
}
<commit_msg>De-duplicate identifier serializer logic.<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 ast;
use ast::*;

impl ast::ComponentValue {
    pub fn to_css(&mut self) -> ~str {
        let mut css = ~"";
        self.to_css_push(&mut css);
        css
    }

    pub fn to_css_push(&self, css: &mut ~str) {
        match *self {
            Ident(ref value) => serialize_identifier(value.as_slice(), css),
            AtKeyword(ref value) => {
                css.push_char('@');
                serialize_identifier(value.as_slice(), css);
            },
            Hash(ref value) | IDHash(ref value) => {
                css.push_char('#');
                serialize_identifier(value.as_slice(), css);
            }
            String(ref value) => serialize_string(value.as_slice(), css),
            URL(ref value) => {
                css.push_str("url(");
                serialize_string(value.as_slice(), css);
                css.push_char(')');
            },
            Delim(value) => css.push_char(value),

            Number(ref value) => css.push_str(value.representation),
            Percentage(ref value) => {
                css.push_str(value.representation);
                css.push_char('%');
            },
            Dimension(ref value, ref unit) => {
                css.push_str(value.representation);
                serialize_identifier(unit.as_slice(), css);
            },

            UnicodeRange(start, end) => {
                css.push_str(format!("U+{:X}", start));
                if end != start {
                    css.push_str(format!("-{:X}", end));
                }
            }

            WhiteSpace => css.push_char(' '),
            Colon => css.push_char(':'),
            Semicolon => css.push_char(';'),
            Comma => css.push_char(','),
            IncludeMatch => css.push_str("~="),
            DashMatch => css.push_str("|="),
            PrefixMatch => css.push_str("^="),
            SuffixMatch => css.push_str("$="),
            SubstringMatch => css.push_str("*="),
            Column => css.push_str("||"),
            CDO => css.push_str("<!--"),
            CDC => css.push_str("-->"),

            Function(ref name, ref arguments) => {
                serialize_identifier(name.as_slice(), css);
                css.push_char('(');
                arguments.iter().to_css_push(css);
                css.push_char(')');
            },
            ParenthesisBlock(ref content) => {
                css.push_char('(');
                content.iter().to_css_push(css);
                css.push_char(')');
            },
            SquareBracketBlock(ref content) => {
                css.push_char('[');
                content.iter().to_css_push(css);
                css.push_char(']');
            },
            CurlyBracketBlock(ref content) => {
                css.push_char('{');
                content.iter().map(|t| match *t { (ref c, _) => c }).to_css_push(css);
                css.push_char('}');
            },

            BadURL => css.push_str("url(<bad url>)"),
            BadString => css.push_str("\"<bad string>\n"),
            CloseParenthesis => css.push_char(')'),
            CloseSquareBracket => css.push_char(']'),
            CloseCurlyBracket => css.push_char('}'),
        }
    }
}

pub fn serialize_identifier(value: &str, css: &mut ~str) {
    // TODO: avoid decoding/re-encoding UTF-8?
    let mut iter = value.iter();
    let mut c = iter.next().unwrap();
    if c == '-' {
        c = match iter.next() {
            None => { css.push_str("\\-"); return },
            Some(c) => { css.push_char('-'); c },
        }
    };
    serialize_char(c, css, /* is_start = */ true);
    for c in iter {
        serialize_char(c, css, /* is_start = */ false);
    }

    #[inline]
    fn serialize_char(c: char, css: &mut ~str, is_start: bool) {
        match c {
            '0'..'9' if is_start => css.push_str(format!("\\\\3{} ", c)),
            '-' if is_start => css.push_str("\\-"),
            '0'..'9' | 'A'..'Z' | 'a'..'z' | '_' | '-' => css.push_char(c),
            _ if c > '\x7F' => css.push_char(c),
            '\n' => css.push_str("\\A "),
            '\r' => css.push_str("\\D "),
            '\x0C' => css.push_str("\\C "),
            _ => { css.push_char('\\'); css.push_char(c) },
        }
    }
}

pub fn serialize_string(value: &str, css: &mut ~str) {
    css.push_char('"');
    // TODO: avoid decoding/re-encoding UTF-8?
    for c in value.iter() {
        match c {
            '"' => css.push_str("\""),
            '\\' => css.push_str("\\\\"),
            '\n' => css.push_str("\\A "),
            '\r' => css.push_str("\\D "),
            '\x0C' => css.push_str("\\C "),
            _ => css.push_char(c),
        }
    }
    css.push_char('"');
}

pub trait ToCss {
    fn to_css(&mut self) -> ~str {
        let mut css = ~"";
        self.to_css_push(&mut css);
        css
    }

    fn to_css_push(&mut self, css: &mut ~str);
}

impl<'self, I: Iterator<&'self ComponentValue>> ToCss for I {
    fn to_css_push(&mut self, css: &mut ~str) {
        let mut previous = match self.next() {
            None => return,
            Some(first) => { first.to_css_push(css); first }
        };
        macro_rules! matches(
            ($value:expr, $($pattern:pat)|+) => (
                match $value { $($pattern)|+ => true, _ => false }
            );
        )
        loop { match self.next() { None => break, Some(component_value) => {
            let (a, b) = (previous, component_value);
            if (
                matches!(*a, Hash(*) | IDHash(*) | AtKeyword(*)) &&
                matches!(*b, Number(*) | Percentage(*) | Ident(*) | Dimension(*) |
                            UnicodeRange(*) | URL(*) | Function(*))
            ) || (
                matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
                matches!(*b, Number(*) | Ident(*) | Dimension(*))
            ) || (
                matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
                matches!(*b, Percentage(*) | UnicodeRange(*) | URL(*) | Function(*))
            ) || (
                matches!(*a, Ident(*)) &&
                matches!(*b, ParenthesisBlock(*))
            ) || (
                matches!(*a, Delim('#') | Delim('@')) &&
                !matches!(*b, WhiteSpace)
            ) || (
                matches!(*a, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
                             Delim('>') | Delim('!')) &&
                !matches!(*b, WhiteSpace)
            ) || (
                !matches!(*a, WhiteSpace) &&
                matches!(*b, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
                             Delim('>') | Delim('!'))
            ) || (
                matches!(*a, Delim('/')) &&
                matches!(*b, Delim('*'))
            ) || (
                matches!(*a, Delim('*')) &&
                matches!(*b, Delim('/'))
            ) {
                css.push_str("/**/")
            }
            component_value.to_css_push(css);
            previous = component_value;
        }}}
    }
}
<|endoftext|>


<commit_before>extern crate typenum;
use matrix::{ColumnPanelMatrix, RowPanelMatrix, Matrix, Subcomputation};
use composables::{PartM, PartN, PartK, PackA, PackB,
                  ForceB, SpawnThreads, ParallelN, TheRest};
use kern::{KernelNM,KernelNMPackingB};
use typenum::{UInt, B0};

// BLIS's constants
type U4080 = UInt<UInt<typenum::U1020, B0>, B0>;
type Nc = U4080;
type Kc = typenum::U256;
type Mc = typenum::U72;
type Mr = typenum::U6;
type Nr = typenum::U8;

// Old constants
// type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
// type Nc = U3000;
// type Kc = typenum::U192;
// type Mc = typenum::U120;
// type Mr = typenum::U4;
// type Nr = typenum::U12;

type Goto<T, MTA, MTB, MTC> =
      PartN<T, MTA, MTB, MTC, Nc,
      PartK<T, MTA, MTB, MTC, Kc,
      PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
      PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
      PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
      ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
      KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>;

pub type GotoDgemm = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3Sub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3 =
    SpawnThreads<f64, Matrix<f64>, GotoDgemm3Sub, Matrix<f64>,
    ForceB<f64, Matrix<f64>,
           Matrix<f64>, Matrix<f64>, Matrix<f64>, GotoDgemm3Sub,
           Matrix<f64>,
    GotoDgemm, GotoDgemm>>;

    // type RootS3 = typenum::U768;
type McL2 = typenum::U72; //typenum::U120;
pub type ColPM<T> = ColumnPanelMatrix<T, Nr>;
pub type RowPM<T> = RowPanelMatrix<T, Mr>;

//type U2040 = UInt<typenum::U1020, B0>;
type L3CNc = U4080;
type L3CMc = typenum::U252;
type L3CKc = typenum::U256;
//Resident C algorithm, inner loops
type L3CInner<T, MTA, MTB, MTC> =
      PartK<T, MTA, MTB, MTC, L3CKc,
      PartM<T, MTA, MTB, MTC, McL2,
      PackA<T, MTA, MTB, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, MTB, MTC, Nr, TheRest,
      KernelNMPackingB<T, RowPM<T>, MTB, MTC, Nr, Mr>>>>>;

type L3CInnerSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;
pub type Dgemm3Sub = L3CInnerSub<f64>;
pub type Dgemm3TmpWidth = L3CNc;
pub type Dgemm3TmpHeight = L3CNc;
type L3BOuter<T, MTA, MTAi, MTBi, MTC> =
      SpawnThreads<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
      PartN<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc,
      PartK<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CMc, // Also the Mc of that algorithm, and outer k -> inner m
      ForceB<T, MTA, MTAi, MTBi, ColPM<T>, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
                L3CInner<T, MTAi, MTBi, ColPM<T>>,
      PartM<T, MTA, ColPM<T>, MTC, McL2,
//    PartK<T, MTA, ColPM<T>, MTC, Kc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>>;

pub type Dgemm3 = L3BOuter<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
<commit_msg>The rather performnat algorithm from yesterday<commit_after>extern crate typenum;
use matrix::{ColumnPanelMatrix, RowPanelMatrix, Matrix, Subcomputation};
use composables::{PartM, PartN, PartK, PackA, PackB,
                  ForceB, SpawnThreads, ParallelN, TheRest};
use kern::{KernelNM,KernelNMPackingB};
use typenum::{UInt, B0};

// BLIS's constants
type U4080 = UInt<UInt<typenum::U1020, B0>, B0>;
type Nc = U4080;
type Kc = typenum::U256;
type Mc = typenum::U72;
type Mr = typenum::U6;
type Nr = typenum::U8;

// Old constants
// type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
// type Nc = U3000;
// type Kc = typenum::U192;
// type Mc = typenum::U120;
// type Mr = typenum::U4;
// type Nr = typenum::U12;

type Goto<T, MTA, MTB, MTC> =
      PartN<T, MTA, MTB, MTC, Nc,
      PartK<T, MTA, MTB, MTC, Kc,
      PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
      PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
      PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
      ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
      KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>;

pub type GotoDgemm = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3Sub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3 =
    SpawnThreads<f64, Matrix<f64>, GotoDgemm3Sub, Matrix<f64>,
    ForceB<f64, Matrix<f64>,
           Matrix<f64>, Matrix<f64>, Matrix<f64>, GotoDgemm3Sub,
           Matrix<f64>,
    GotoDgemm, GotoDgemm>>;

    // type RootS3 = typenum::U768;
type McL2 = typenum::U72; //typenum::U120;
pub type ColPM<T> = ColumnPanelMatrix<T, Nr>;
pub type RowPM<T> = RowPanelMatrix<T, Mr>;

type U2040 = UInt<typenum::U1020, B0>;
type L3CNc = U2040;
type L3CMc = typenum::U252;
type L3CKc = typenum::U256;
//Resident C algorithm, inner loops
type L3CInner<T, MTA, MTB, MTC> =
      PartK<T, MTA, MTB, MTC, L3CKc,
      PackB<T, MTA, MTB, MTC, ColPM<T>,
      PartM<T, MTA, ColPM<T>, MTC, McL2,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>;

type L3CInnerSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;
pub type Dgemm3Sub = L3CInnerSub<f64>;
pub type Dgemm3TmpWidth = L3CNc;
pub type Dgemm3TmpHeight = L3CNc;
type L3BOuter<T, MTA, MTAi, MTBi, MTC> =
      SpawnThreads<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
      PartN<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc,
      PartK<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CMc, // Also the Mc of that algorithm, and outer k -> inner m
      ForceB<T, MTA, MTAi, MTBi, ColPM<T>, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
                L3CInner<T, MTAi, MTBi, ColPM<T>>,
      PartM<T, MTA, ColPM<T>, MTC, McL2,
//    PartK<T, MTA, ColPM<T>, MTC, Kc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>>;

pub type Dgemm3 = L3BOuter<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
<|endoftext|>