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

use attributes::Attribute;
use clip_path::NodeClipPath;
use defs::Defs;
use filters::{
    blend::Blend,
    color_matrix::ColorMatrix,
    component_transfer::{ComponentTransfer, FuncX},
    composite::Composite,
    convolve_matrix::ConvolveMatrix,
    displacement_map::DisplacementMap,
    flood::Flood,
    gaussian_blur::GaussianBlur,
    image::Image,
    light::{light_source::LightSource, lighting::Lighting},
    merge::{Merge, MergeNode},
    morphology::Morphology,
    node::NodeFilter,
    offset::Offset,
    tile::Tile,
    turbulence::Turbulence,
};
use gradient::NodeGradient;
use image::NodeImage;
use link::NodeLink;
use marker::NodeMarker;
use mask::NodeMask;
use node::*;
use pattern::NodePattern;
use property_bag::PropertyBag;
use shapes::{NodeCircle, NodeEllipse, NodeLine, NodePath, NodePoly, NodeRect};
use stop::NodeStop;
use structure::{NodeDefs, NodeGroup, NodeSvg, NodeSwitch, NodeSymbol, NodeUse};
use style::NodeStyle;
use text::{NodeTRef, NodeTSpan, NodeText};

macro_rules! node_create_fn {
    ($name:ident, $node_type:ident, $new_fn:expr) => {
        fn $name(
            element_name: &str,
            id: Option<&str>,
            class: Option<&str>,
            parent: Option<&RsvgNode>,
        ) -> RsvgNode {
            node_new(
                NodeType::$node_type,
                parent,
                element_name,
                id,
                class,
                Box::new($new_fn()),
            )
        }
    };
}

node_create_fn!(create_circle, Circle, NodeCircle::new);
node_create_fn!(create_clip_path, ClipPath, NodeClipPath::new);
node_create_fn!(create_blend, FilterPrimitiveBlend, Blend::new);
node_create_fn!(
    create_color_matrix,
    FilterPrimitiveColorMatrix,
    ColorMatrix::new
);
node_create_fn!(
    create_component_transfer,
    FilterPrimitiveComponentTransfer,
    ComponentTransfer::new
);
node_create_fn!(
    create_component_transfer_func_a,
    ComponentTransferFunctionA,
    FuncX::new_a
);
node_create_fn!(
    create_component_transfer_func_b,
    ComponentTransferFunctionB,
    FuncX::new_b
);
node_create_fn!(
    create_component_transfer_func_g,
    ComponentTransferFunctionG,
    FuncX::new_g
);
node_create_fn!(
    create_component_transfer_func_r,
    ComponentTransferFunctionR,
    FuncX::new_r
);
node_create_fn!(create_composite, FilterPrimitiveComposite, Composite::new);
node_create_fn!(
    create_convolve_matrix,
    FilterPrimitiveConvolveMatrix,
    ConvolveMatrix::new
);
node_create_fn!(create_defs, Defs, NodeDefs::new);
node_create_fn!(
    create_diffuse_lighting,
    FilterPrimitiveDiffuseLighting,
    Lighting::new_diffuse
);
node_create_fn!(
    create_distant_light,
    DistantLight,
    LightSource::new_distant_light
);
node_create_fn!(
    create_displacement_map,
    FilterPrimitiveDisplacementMap,
    DisplacementMap::new
);
node_create_fn!(create_ellipse, Ellipse, NodeEllipse::new);
node_create_fn!(create_filter, Filter, NodeFilter::new);
node_create_fn!(create_flood, FilterPrimitiveFlood, Flood::new);
node_create_fn!(
    create_gaussian_blur,
    FilterPrimitiveGaussianBlur,
    GaussianBlur::new
);
node_create_fn!(create_group, Group, NodeGroup::new);
node_create_fn!(create_image, Image, NodeImage::new);
node_create_fn!(create_fe_image, FilterPrimitiveImage, Image::new);
node_create_fn!(
    create_linear_gradient,
    LinearGradient,
    NodeGradient::new_linear
);
node_create_fn!(create_line, Line, NodeLine::new);
node_create_fn!(create_link, Link, NodeLink::new);
node_create_fn!(create_marker, Marker, NodeMarker::new);
node_create_fn!(create_mask, Mask, NodeMask::new);
node_create_fn!(create_merge, FilterPrimitiveMerge, Merge::new);
node_create_fn!(create_merge_node, FilterPrimitiveMergeNode, MergeNode::new);
node_create_fn!(
    create_morphology,
    FilterPrimitiveMorphology,
    Morphology::new
);
node_create_fn!(create_offset, FilterPrimitiveOffset, Offset::new);
node_create_fn!(create_path, Path, NodePath::new);
node_create_fn!(create_pattern, Pattern, NodePattern::new);
node_create_fn!(create_point_light, PointLight, LightSource::new_point_light);
node_create_fn!(create_polygon, Polygon, NodePoly::new_closed);
node_create_fn!(create_polyline, Polyline, NodePoly::new_open);
node_create_fn!(
    create_radial_gradient,
    RadialGradient,
    NodeGradient::new_radial
);
node_create_fn!(create_rect, Rect, NodeRect::new);
node_create_fn!(
    create_specular_lighting,
    FilterPrimitiveSpecularLighting,
    Lighting::new_specular
);
node_create_fn!(create_spot_light, SpotLight, LightSource::new_spot_light);
node_create_fn!(create_stop, Stop, NodeStop::new);
node_create_fn!(create_style, Style, NodeStyle::new);
node_create_fn!(create_svg, Svg, NodeSvg::new);
node_create_fn!(create_switch, Switch, NodeSwitch::new);
node_create_fn!(create_symbol, Symbol, NodeSymbol::new);
node_create_fn!(create_text, Text, NodeText::new);
node_create_fn!(create_tref, TRef, NodeTRef::new);
node_create_fn!(create_tspan, TSpan, NodeTSpan::new);
node_create_fn!(create_tile, FilterPrimitiveTile, Tile::new);
node_create_fn!(
    create_turbulence,
    FilterPrimitiveTurbulence,
    Turbulence::new
);
node_create_fn!(create_use, Use, NodeUse::new);

type NodeCreateFn =
    fn(name: &str, id: Option<&str>, class: Option<&str>, parent: Option<&RsvgNode>) -> RsvgNode;

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        h.insert("a",                   (true,  create_link as NodeCreateFn));
        /* h.insert("altGlyph",         (true,  as NodeCreateFn)); */
        /* h.insert("altGlyphDef",      (false, as NodeCreateFn)); */
        /* h.insert("altGlyphItem",     (false, as NodeCreateFn)); */
        /* h.insert("animate",          (false, as NodeCreateFn)); */
        /* h.insert("animateColor",     (false, as NodeCreateFn)); */
        /* h.insert("animateMotion",    (false, as NodeCreateFn)); */
        /* h.insert("animateTransform", (false, as NodeCreateFn)); */
        h.insert("circle",              (true,  create_circle as NodeCreateFn));
        h.insert("clipPath",            (true,  create_clip_path as NodeCreateFn));
        /* h.insert("color-profile",    (false, as NodeCreateFn)); */
        h.insert("conicalGradient",     (true,  create_radial_gradient as NodeCreateFn));
        /* h.insert("cursor",           (false, as NodeCreateFn)); */
        h.insert("defs",                (true,  create_defs as NodeCreateFn));
        /* h.insert("desc",             (true,  as NodeCreateFn)); */
        h.insert("ellipse",             (true,  create_ellipse as NodeCreateFn));
        h.insert("feBlend",             (true,  create_blend as NodeCreateFn));
        h.insert("feColorMatrix",       (true,  create_color_matrix as NodeCreateFn));
        h.insert("feComponentTransfer", (true,  create_component_transfer as NodeCreateFn));
        h.insert("feComposite",         (true,  create_composite as NodeCreateFn));
        h.insert("feConvolveMatrix",    (true,  create_convolve_matrix as NodeCreateFn));
        h.insert("feDiffuseLighting",   (true,  create_diffuse_lighting as NodeCreateFn));
        h.insert("feDisplacementMap",   (true,  create_displacement_map as NodeCreateFn));
        h.insert("feDistantLight",      (false, create_distant_light as NodeCreateFn));
        h.insert("feFuncA",             (false, create_component_transfer_func_a as NodeCreateFn));
        h.insert("feFuncB",             (false, create_component_transfer_func_b as NodeCreateFn));
        h.insert("feFuncG",             (false, create_component_transfer_func_g as NodeCreateFn));
        h.insert("feFuncR",             (false, create_component_transfer_func_r as NodeCreateFn));
        h.insert("feFlood",             (true,  create_flood as NodeCreateFn));
        h.insert("feGaussianBlur",      (true,  create_gaussian_blur as NodeCreateFn));
        h.insert("feImage",             (true,  create_fe_image as NodeCreateFn));
        h.insert("feMerge",             (true,  create_merge as NodeCreateFn));
        h.insert("feMergeNode",         (false, create_merge_node as NodeCreateFn));
        h.insert("feMorphology",        (true,  create_morphology as NodeCreateFn));
        h.insert("feOffset",            (true,  create_offset as NodeCreateFn));
        h.insert("fePointLight",        (false, create_point_light as NodeCreateFn));
        h.insert("feSpecularLighting",  (true,  create_specular_lighting as NodeCreateFn));
        h.insert("feSpotLight",         (false, create_spot_light as NodeCreateFn));
        h.insert("feTile",              (true,  create_tile as NodeCreateFn));
        h.insert("feTurbulence",        (true,  create_turbulence as NodeCreateFn));
        h.insert("filter",              (true,  create_filter as NodeCreateFn));
        /* h.insert("font",             (true,  as NodeCreateFn)); */
        /* h.insert("font-face",        (false, as NodeCreateFn)); */
        /* h.insert("font-face-format", (false, as NodeCreateFn)); */
        /* h.insert("font-face-name",   (false, as NodeCreateFn)); */
        /* h.insert("font-face-src",    (false, as NodeCreateFn)); */
        /* h.insert("font-face-uri",    (false, as NodeCreateFn)); */
        /* h.insert("foreignObject",    (true,  as NodeCreateFn)); */
        h.insert("g",                   (true,  create_group as NodeCreateFn));
        /* h.insert("glyph",            (true,  as NodeCreateFn)); */
        /* h.insert("glyphRef",         (true,  as NodeCreateFn)); */
        /* h.insert("hkern",            (false, as NodeCreateFn)); */
        h.insert("image",               (true,  create_image as NodeCreateFn));
        h.insert("line",                (true,  create_line as NodeCreateFn));
        h.insert("linearGradient",      (true,  create_linear_gradient as NodeCreateFn));
        h.insert("marker",              (true,  create_marker as NodeCreateFn));
        h.insert("mask",                (true,  create_mask as NodeCreateFn));
        /* h.insert("metadata",         (false, as NodeCreateFn)); */
        /* h.insert("missing-glyph",    (true,  as NodeCreateFn)); */
        /* h.insert("mpath",            (false, as NodeCreateFn)); */
        h.insert("multiImage",          (false, create_switch as NodeCreateFn)); // hack to make multiImage sort-of work
        h.insert("path",                (true,  create_path as NodeCreateFn));
        h.insert("pattern",             (true,  create_pattern as NodeCreateFn));
        h.insert("polygon",             (true,  create_polygon as NodeCreateFn));
        h.insert("polyline",            (true,  create_polyline as NodeCreateFn));
        h.insert("radialGradient",      (true,  create_radial_gradient as NodeCreateFn));
        h.insert("rect",                (true,  create_rect as NodeCreateFn));
        /* h.insert("script",           (false, as NodeCreateFn)); */
        /* h.insert("set",              (false, as NodeCreateFn)); */
        h.insert("stop",                (true,  create_stop as NodeCreateFn));
        h.insert("style",               (false, create_style as NodeCreateFn));
        h.insert("subImage",            (false, create_group as NodeCreateFn));
        h.insert("subImageRef",         (false, create_image as NodeCreateFn));
        h.insert("svg",                 (true,  create_svg as NodeCreateFn));
        h.insert("switch",              (true,  create_switch as NodeCreateFn));
        h.insert("symbol",              (true,  create_symbol as NodeCreateFn));
        h.insert("text",                (true,  create_text as NodeCreateFn));
        /* h.insert("textPath",         (true,  as NodeCreateFn)); */
        /* h.insert("title",            (true,  as NodeCreateFn)); */
        h.insert("tref",                (true,  create_tref as NodeCreateFn));
        h.insert("tspan",               (true,  create_tspan as NodeCreateFn));
        h.insert("use",                 (true,  create_use as NodeCreateFn));
        /* h.insert("view",             (false, as NodeCreateFn)); */
        /* h.insert("vkern",            (false, as NodeCreateFn)); */
        h
    };
}

pub fn create_node_and_register_id(
    name: &str,
    parent: Option<&RsvgNode>,
    pbag: &PropertyBag,
    defs: &mut Defs,
) -> RsvgNode {
    let mut id = None;
    let mut class = None;

    for (_key, attr, value) in pbag.iter() {
        match attr {
            Attribute::Id => id = Some(value),
            Attribute::Class => class = Some(value),
            _ => (),
        }
    }

    let &(supports_class, create_fn) = match NODE_CREATORS.get(name) {
        Some(c) => c,
        // Whenever we encounter a node we don't understand, represent it as a defs.
        // This is like a group, but it doesn't do any rendering of children.  The
        // effect is that we will ignore all children of unknown elements.
        None => &(true, create_defs as NodeCreateFn),
    };

    if !supports_class {
        class = None;
    };

    let node = create_fn(name, id, class, parent);

    if id.is_some() {
        defs.insert(id.unwrap(), &node);
    }

    node
}
<commit_msg>node: clarify hacks for partially supported elements<commit_after>use std::collections::HashMap;

use attributes::Attribute;
use clip_path::NodeClipPath;
use defs::Defs;
use filters::{
    blend::Blend,
    color_matrix::ColorMatrix,
    component_transfer::{ComponentTransfer, FuncX},
    composite::Composite,
    convolve_matrix::ConvolveMatrix,
    displacement_map::DisplacementMap,
    flood::Flood,
    gaussian_blur::GaussianBlur,
    image::Image,
    light::{light_source::LightSource, lighting::Lighting},
    merge::{Merge, MergeNode},
    morphology::Morphology,
    node::NodeFilter,
    offset::Offset,
    tile::Tile,
    turbulence::Turbulence,
};
use gradient::NodeGradient;
use image::NodeImage;
use link::NodeLink;
use marker::NodeMarker;
use mask::NodeMask;
use node::*;
use pattern::NodePattern;
use property_bag::PropertyBag;
use shapes::{NodeCircle, NodeEllipse, NodeLine, NodePath, NodePoly, NodeRect};
use stop::NodeStop;
use structure::{NodeDefs, NodeGroup, NodeSvg, NodeSwitch, NodeSymbol, NodeUse};
use style::NodeStyle;
use text::{NodeTRef, NodeTSpan, NodeText};

macro_rules! node_create_fn {
    ($name:ident, $node_type:ident, $new_fn:expr) => {
        fn $name(
            element_name: &str,
            id: Option<&str>,
            class: Option<&str>,
            parent: Option<&RsvgNode>,
        ) -> RsvgNode {
            node_new(
                NodeType::$node_type,
                parent,
                element_name,
                id,
                class,
                Box::new($new_fn()),
            )
        }
    };
}

node_create_fn!(create_circle, Circle, NodeCircle::new);
node_create_fn!(create_clip_path, ClipPath, NodeClipPath::new);
node_create_fn!(create_blend, FilterPrimitiveBlend, Blend::new);
node_create_fn!(
    create_color_matrix,
    FilterPrimitiveColorMatrix,
    ColorMatrix::new
);
node_create_fn!(
    create_component_transfer,
    FilterPrimitiveComponentTransfer,
    ComponentTransfer::new
);
node_create_fn!(
    create_component_transfer_func_a,
    ComponentTransferFunctionA,
    FuncX::new_a
);
node_create_fn!(
    create_component_transfer_func_b,
    ComponentTransferFunctionB,
    FuncX::new_b
);
node_create_fn!(
    create_component_transfer_func_g,
    ComponentTransferFunctionG,
    FuncX::new_g
);
node_create_fn!(
    create_component_transfer_func_r,
    ComponentTransferFunctionR,
    FuncX::new_r
);
node_create_fn!(create_composite, FilterPrimitiveComposite, Composite::new);
node_create_fn!(
    create_convolve_matrix,
    FilterPrimitiveConvolveMatrix,
    ConvolveMatrix::new
);
node_create_fn!(create_defs, Defs, NodeDefs::new);
node_create_fn!(
    create_diffuse_lighting,
    FilterPrimitiveDiffuseLighting,
    Lighting::new_diffuse
);
node_create_fn!(
    create_distant_light,
    DistantLight,
    LightSource::new_distant_light
);
node_create_fn!(
    create_displacement_map,
    FilterPrimitiveDisplacementMap,
    DisplacementMap::new
);
node_create_fn!(create_ellipse, Ellipse, NodeEllipse::new);
node_create_fn!(create_filter, Filter, NodeFilter::new);
node_create_fn!(create_flood, FilterPrimitiveFlood, Flood::new);
node_create_fn!(
    create_gaussian_blur,
    FilterPrimitiveGaussianBlur,
    GaussianBlur::new
);
node_create_fn!(create_group, Group, NodeGroup::new);
node_create_fn!(create_image, Image, NodeImage::new);
node_create_fn!(create_fe_image, FilterPrimitiveImage, Image::new);
node_create_fn!(
    create_linear_gradient,
    LinearGradient,
    NodeGradient::new_linear
);
node_create_fn!(create_line, Line, NodeLine::new);
node_create_fn!(create_link, Link, NodeLink::new);
node_create_fn!(create_marker, Marker, NodeMarker::new);
node_create_fn!(create_mask, Mask, NodeMask::new);
node_create_fn!(create_merge, FilterPrimitiveMerge, Merge::new);
node_create_fn!(create_merge_node, FilterPrimitiveMergeNode, MergeNode::new);
node_create_fn!(
    create_morphology,
    FilterPrimitiveMorphology,
    Morphology::new
);
node_create_fn!(create_offset, FilterPrimitiveOffset, Offset::new);
node_create_fn!(create_path, Path, NodePath::new);
node_create_fn!(create_pattern, Pattern, NodePattern::new);
node_create_fn!(create_point_light, PointLight, LightSource::new_point_light);
node_create_fn!(create_polygon, Polygon, NodePoly::new_closed);
node_create_fn!(create_polyline, Polyline, NodePoly::new_open);
node_create_fn!(
    create_radial_gradient,
    RadialGradient,
    NodeGradient::new_radial
);
node_create_fn!(create_rect, Rect, NodeRect::new);
node_create_fn!(
    create_specular_lighting,
    FilterPrimitiveSpecularLighting,
    Lighting::new_specular
);
node_create_fn!(create_spot_light, SpotLight, LightSource::new_spot_light);
node_create_fn!(create_stop, Stop, NodeStop::new);
node_create_fn!(create_style, Style, NodeStyle::new);
node_create_fn!(create_svg, Svg, NodeSvg::new);
node_create_fn!(create_switch, Switch, NodeSwitch::new);
node_create_fn!(create_symbol, Symbol, NodeSymbol::new);
node_create_fn!(create_text, Text, NodeText::new);
node_create_fn!(create_tref, TRef, NodeTRef::new);
node_create_fn!(create_tspan, TSpan, NodeTSpan::new);
node_create_fn!(create_tile, FilterPrimitiveTile, Tile::new);
node_create_fn!(
    create_turbulence,
    FilterPrimitiveTurbulence,
    Turbulence::new
);
node_create_fn!(create_use, Use, NodeUse::new);

// hack to partially support conical gradient
node_create_fn!(
    create_conical_gradient,
    RadialGradient,
    NodeGradient::new_radial
);

// hack to make multiImage sort-of work
node_create_fn!(create_multi_image, Switch, NodeSwitch::new);
node_create_fn!(create_sub_image, Group, NodeGroup::new);
node_create_fn!(create_sub_image_ref, Image, NodeImage::new);

type NodeCreateFn =
    fn(name: &str, id: Option<&str>, class: Option<&str>, parent: Option<&RsvgNode>) -> RsvgNode;

lazy_static! {
    // Lines in comments are elements that we don't support.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    static ref NODE_CREATORS: HashMap<&'static str, (bool, NodeCreateFn)> = {
        let mut h = HashMap::new();
        h.insert("a",                   (true,  create_link as NodeCreateFn));
        /* h.insert("altGlyph",         (true,  as NodeCreateFn)); */
        /* h.insert("altGlyphDef",      (false, as NodeCreateFn)); */
        /* h.insert("altGlyphItem",     (false, as NodeCreateFn)); */
        /* h.insert("animate",          (false, as NodeCreateFn)); */
        /* h.insert("animateColor",     (false, as NodeCreateFn)); */
        /* h.insert("animateMotion",    (false, as NodeCreateFn)); */
        /* h.insert("animateTransform", (false, as NodeCreateFn)); */
        h.insert("circle",              (true,  create_circle as NodeCreateFn));
        h.insert("clipPath",            (true,  create_clip_path as NodeCreateFn));
        /* h.insert("color-profile",    (false, as NodeCreateFn)); */
        h.insert("conicalGradient",     (true,  create_conical_gradient as NodeCreateFn));
        /* h.insert("cursor",           (false, as NodeCreateFn)); */
        h.insert("defs",                (true,  create_defs as NodeCreateFn));
        /* h.insert("desc",             (true,  as NodeCreateFn)); */
        h.insert("ellipse",             (true,  create_ellipse as NodeCreateFn));
        h.insert("feBlend",             (true,  create_blend as NodeCreateFn));
        h.insert("feColorMatrix",       (true,  create_color_matrix as NodeCreateFn));
        h.insert("feComponentTransfer", (true,  create_component_transfer as NodeCreateFn));
        h.insert("feComposite",         (true,  create_composite as NodeCreateFn));
        h.insert("feConvolveMatrix",    (true,  create_convolve_matrix as NodeCreateFn));
        h.insert("feDiffuseLighting",   (true,  create_diffuse_lighting as NodeCreateFn));
        h.insert("feDisplacementMap",   (true,  create_displacement_map as NodeCreateFn));
        h.insert("feDistantLight",      (false, create_distant_light as NodeCreateFn));
        h.insert("feFuncA",             (false, create_component_transfer_func_a as NodeCreateFn));
        h.insert("feFuncB",             (false, create_component_transfer_func_b as NodeCreateFn));
        h.insert("feFuncG",             (false, create_component_transfer_func_g as NodeCreateFn));
        h.insert("feFuncR",             (false, create_component_transfer_func_r as NodeCreateFn));
        h.insert("feFlood",             (true,  create_flood as NodeCreateFn));
        h.insert("feGaussianBlur",      (true,  create_gaussian_blur as NodeCreateFn));
        h.insert("feImage",             (true,  create_fe_image as NodeCreateFn));
        h.insert("feMerge",             (true,  create_merge as NodeCreateFn));
        h.insert("feMergeNode",         (false, create_merge_node as NodeCreateFn));
        h.insert("feMorphology",        (true,  create_morphology as NodeCreateFn));
        h.insert("feOffset",            (true,  create_offset as NodeCreateFn));
        h.insert("fePointLight",        (false, create_point_light as NodeCreateFn));
        h.insert("feSpecularLighting",  (true,  create_specular_lighting as NodeCreateFn));
        h.insert("feSpotLight",         (false, create_spot_light as NodeCreateFn));
        h.insert("feTile",              (true,  create_tile as NodeCreateFn));
        h.insert("feTurbulence",        (true,  create_turbulence as NodeCreateFn));
        h.insert("filter",              (true,  create_filter as NodeCreateFn));
        /* h.insert("font",             (true,  as NodeCreateFn)); */
        /* h.insert("font-face",        (false, as NodeCreateFn)); */
        /* h.insert("font-face-format", (false, as NodeCreateFn)); */
        /* h.insert("font-face-name",   (false, as NodeCreateFn)); */
        /* h.insert("font-face-src",    (false, as NodeCreateFn)); */
        /* h.insert("font-face-uri",    (false, as NodeCreateFn)); */
        /* h.insert("foreignObject",    (true,  as NodeCreateFn)); */
        h.insert("g",                   (true,  create_group as NodeCreateFn));
        /* h.insert("glyph",            (true,  as NodeCreateFn)); */
        /* h.insert("glyphRef",         (true,  as NodeCreateFn)); */
        /* h.insert("hkern",            (false, as NodeCreateFn)); */
        h.insert("image",               (true,  create_image as NodeCreateFn));
        h.insert("line",                (true,  create_line as NodeCreateFn));
        h.insert("linearGradient",      (true,  create_linear_gradient as NodeCreateFn));
        h.insert("marker",              (true,  create_marker as NodeCreateFn));
        h.insert("mask",                (true,  create_mask as NodeCreateFn));
        /* h.insert("metadata",         (false, as NodeCreateFn)); */
        /* h.insert("missing-glyph",    (true,  as NodeCreateFn)); */
        /* h.insert("mpath",            (false, as NodeCreateFn)); */
        h.insert("multiImage",          (false, create_multi_image as NodeCreateFn));
        h.insert("path",                (true,  create_path as NodeCreateFn));
        h.insert("pattern",             (true,  create_pattern as NodeCreateFn));
        h.insert("polygon",             (true,  create_polygon as NodeCreateFn));
        h.insert("polyline",            (true,  create_polyline as NodeCreateFn));
        h.insert("radialGradient",      (true,  create_radial_gradient as NodeCreateFn));
        h.insert("rect",                (true,  create_rect as NodeCreateFn));
        /* h.insert("script",           (false, as NodeCreateFn)); */
        /* h.insert("set",              (false, as NodeCreateFn)); */
        h.insert("stop",                (true,  create_stop as NodeCreateFn));
        h.insert("style",               (false, create_style as NodeCreateFn));
        h.insert("subImage",            (false, create_sub_image as NodeCreateFn));
        h.insert("subImageRef",         (false, create_sub_image_ref as NodeCreateFn));
        h.insert("svg",                 (true,  create_svg as NodeCreateFn));
        h.insert("switch",              (true,  create_switch as NodeCreateFn));
        h.insert("symbol",              (true,  create_symbol as NodeCreateFn));
        h.insert("text",                (true,  create_text as NodeCreateFn));
        /* h.insert("textPath",         (true,  as NodeCreateFn)); */
        /* h.insert("title",            (true,  as NodeCreateFn)); */
        h.insert("tref",                (true,  create_tref as NodeCreateFn));
        h.insert("tspan",               (true,  create_tspan as NodeCreateFn));
        h.insert("use",                 (true,  create_use as NodeCreateFn));
        /* h.insert("view",             (false, as NodeCreateFn)); */
        /* h.insert("vkern",            (false, as NodeCreateFn)); */
        h
    };
}

pub fn create_node_and_register_id(
    name: &str,
    parent: Option<&RsvgNode>,
    pbag: &PropertyBag,
    defs: &mut Defs,
) -> RsvgNode {
    let mut id = None;
    let mut class = None;

    for (_key, attr, value) in pbag.iter() {
        match attr {
            Attribute::Id => id = Some(value),
            Attribute::Class => class = Some(value),
            _ => (),
        }
    }

    let &(supports_class, create_fn) = match NODE_CREATORS.get(name) {
        Some(c) => c,
        // Whenever we encounter a node we don't understand, represent it as a defs.
        // This is like a group, but it doesn't do any rendering of children.  The
        // effect is that we will ignore all children of unknown elements.
        None => &(true, create_defs as NodeCreateFn),
    };

    if !supports_class {
        class = None;
    };

    let node = create_fn(name, id, class, parent);

    if id.is_some() {
        defs.insert(id.unwrap(), &node);
    }

    node
}
<|endoftext|>


<commit_before>use cssparser::{BasicParseError, Parser, Token};

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::{LengthBoth, LengthHorizontal, LengthUnit, POINTS_PER_INCH};
use crate::parsers::{Parse, ParseError};
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(LengthBoth),
}

impl FontSizeSpec {
    pub fn value(&self) -> LengthBoth {
        match self {
            FontSizeSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => LengthBoth::new(size.length() / 1.2, size.unit()),
            FontSizeSpec::Larger => LengthBoth::new(size.length() * 1.2, size.unit()),
            FontSizeSpec::XXSmall => LengthBoth::new(compute_points(-3.0), LengthUnit::In),
            FontSizeSpec::XSmall => LengthBoth::new(compute_points(-2.0), LengthUnit::In),
            FontSizeSpec::Small => LengthBoth::new(compute_points(-1.0), LengthUnit::In),
            FontSizeSpec::Medium => LengthBoth::new(compute_points(0.0), LengthUnit::In),
            FontSizeSpec::Large => LengthBoth::new(compute_points(1.0), LengthUnit::In),
            FontSizeSpec::XLarge => LengthBoth::new(compute_points(2.0), LengthUnit::In),
            FontSizeSpec::XXLarge => LengthBoth::new(compute_points(3.0), LengthUnit::In),
            FontSizeSpec::Value(s) if s.unit() == LengthUnit::Percent => {
                LengthBoth::new(size.length() * s.length(), size.unit())
            }
            FontSizeSpec::Value(s) => s.clone(),
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontSizeSpec, crate::error::ValueErrorKind> {
        let parser_state = parser.state();

        LengthBoth::parse(parser)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        crate::error::ValueErrorKind::Parse(crate::parsers::ParseError::new(
                            "expected token",
                        ))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontWeightSpec, crate::error::ValueErrorKind> {
        if let Ok(r) = parser.try_parse(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            })
        {
            Ok(r)
        } else {
            Err(ValueErrorKind::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(LengthHorizontal),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> LengthHorizontal {
        match self {
            LetterSpacingSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => LengthHorizontal::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => s.clone(),
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
    ) -> Result<LetterSpacingSpec, crate::error::ValueErrorKind> {
        let parser_state = parser.state();

        LengthHorizontal::parse(parser)
            .and_then(|s| Ok(LetterSpacingSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        crate::error::ValueErrorKind::Parse(crate::parsers::ParseError::new(
                            "expected token",
                        ))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        if let "normal" = cow.as_ref() {
                            return Ok(LetterSpacingSpec::Normal);
                        }
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::from(ParseError::new("expected font family")))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<commit_msg>font_props: do not clone Copy values<commit_after>use cssparser::{BasicParseError, Parser, Token};

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::{LengthBoth, LengthHorizontal, LengthUnit, POINTS_PER_INCH};
use crate::parsers::{Parse, ParseError};
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(LengthBoth),
}

impl FontSizeSpec {
    pub fn value(&self) -> LengthBoth {
        match self {
            FontSizeSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => LengthBoth::new(size.length() / 1.2, size.unit()),
            FontSizeSpec::Larger => LengthBoth::new(size.length() * 1.2, size.unit()),
            FontSizeSpec::XXSmall => LengthBoth::new(compute_points(-3.0), LengthUnit::In),
            FontSizeSpec::XSmall => LengthBoth::new(compute_points(-2.0), LengthUnit::In),
            FontSizeSpec::Small => LengthBoth::new(compute_points(-1.0), LengthUnit::In),
            FontSizeSpec::Medium => LengthBoth::new(compute_points(0.0), LengthUnit::In),
            FontSizeSpec::Large => LengthBoth::new(compute_points(1.0), LengthUnit::In),
            FontSizeSpec::XLarge => LengthBoth::new(compute_points(2.0), LengthUnit::In),
            FontSizeSpec::XXLarge => LengthBoth::new(compute_points(3.0), LengthUnit::In),
            FontSizeSpec::Value(s) if s.unit() == LengthUnit::Percent => {
                LengthBoth::new(size.length() * s.length(), size.unit())
            }
            FontSizeSpec::Value(s) => *s,
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontSizeSpec, crate::error::ValueErrorKind> {
        let parser_state = parser.state();

        LengthBoth::parse(parser)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        crate::error::ValueErrorKind::Parse(crate::parsers::ParseError::new(
                            "expected token",
                        ))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<FontWeightSpec, crate::error::ValueErrorKind> {
        if let Ok(r) = parser.try_parse(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            })
        {
            Ok(r)
        } else {
            Err(ValueErrorKind::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(LengthHorizontal),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> LengthHorizontal {
        match self {
            LetterSpacingSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => LengthHorizontal::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => *s,
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
    ) -> Result<LetterSpacingSpec, crate::error::ValueErrorKind> {
        let parser_state = parser.state();

        LengthHorizontal::parse(parser)
            .and_then(|s| Ok(LetterSpacingSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        crate::error::ValueErrorKind::Parse(crate::parsers::ParseError::new(
                            "expected token",
                        ))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        if let "normal" = cow.as_ref() {
                            return Ok(LetterSpacingSpec::Normal);
                        }
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::from(ParseError::new("expected font family")))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(LengthHorizontal::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong")));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<|endoftext|>


<commit_before>extern crate base64;
#[macro_use]
extern crate criterion;
extern crate rand;

use base64::display;
use base64::{
    decode, decode_config_buf, decode_config_slice, encode, encode_config_buf, encode_config_slice,
    write, Config,
};

use criterion::{black_box, Bencher, Criterion, ParameterizedBenchmark, Throughput};
use rand::{FromEntropy, Rng};
use std::io::{self, Read, Write};

const TEST_CONFIG: Config = base64::STANDARD;

fn do_decode_bench(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    b.iter(|| {
        let orig = decode(&encoded);
        black_box(&orig);
    });
}

fn do_decode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    b.iter(|| {
        decode_config_buf(&encoded, TEST_CONFIG, &mut buf).unwrap();
        black_box(&buf);
        buf.clear();
    });
}

fn do_decode_bench_slice(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    buf.resize(size, 0);
    b.iter(|| {
        decode_config_slice(&encoded, TEST_CONFIG, &mut buf).unwrap();
        black_box(&buf);
    });
}

fn do_decode_bench_stream(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    buf.resize(size, 0);
    buf.truncate(0);

    b.iter(|| {
        let mut cursor = io::Cursor::new(&encoded[..]);
        let mut decoder = base64::read::DecoderReader::new(&mut cursor, TEST_CONFIG);
        decoder.read_to_end(&mut buf).unwrap();
        buf.clear();
        black_box(&buf);
    });
}

fn do_encode_bench(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    b.iter(|| {
        let e = encode(&v);
        black_box(&e);
    });
}

fn do_encode_bench_display(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    b.iter(|| {
        let e = format!("{}", display::Base64Display::with_config(&v, TEST_CONFIG));
        black_box(&e);
    });
}

fn do_encode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = String::new();
    b.iter(|| {
        encode_config_buf(&v, TEST_CONFIG, &mut buf);
        buf.clear();
    });
}

fn do_encode_bench_slice(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = Vec::new();
    // conservative estimate of encoded size
    buf.resize(v.len() * 2, 0);
    b.iter(|| {
        encode_config_slice(&v, TEST_CONFIG, &mut buf);
    });
}

fn do_encode_bench_stream(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = Vec::new();

    buf.reserve(size * 2);
    b.iter(|| {
        buf.clear();
        let mut stream_enc = write::EncoderWriter::new(&mut buf, TEST_CONFIG);
        stream_enc.write_all(&v).unwrap();
        stream_enc.flush().unwrap();
    });
}

fn fill(v: &mut Vec<u8>) {
    let cap = v.capacity();
    // weak randomness is plenty; we just want to not be completely friendly to the branch predictor
    let mut r = rand::rngs::SmallRng::from_entropy();
    while v.len() < cap {
        v.push(r.gen::<u8>());
    }
}

const BYTE_SIZES: [usize; 5] = [3, 50, 100, 500, 3 * 1024];

// Benchmarks over these byte sizes take longer so we will run fewer samples to
// keep the benchmark runtime reasonable.
const LARGE_BYTE_SIZES: [usize; 3] = [3 * 1024 * 1024, 10 * 1024 * 1024, 30 * 1024 * 1024];

fn encode_benchmarks(byte_sizes: &[usize]) -> ParameterizedBenchmark<usize> {
    ParameterizedBenchmark::new("encode", do_encode_bench, byte_sizes.iter().cloned())
        .warm_up_time(std::time::Duration::from_millis(500))
        .measurement_time(std::time::Duration::from_secs(3))
        .throughput(|s| Throughput::Bytes(*s as u64))
        .with_function("encode_display", do_encode_bench_display)
        .with_function("encode_reuse_buf", do_encode_bench_reuse_buf)
        .with_function("encode_slice", do_encode_bench_slice)
        .with_function("encode_reuse_buf_stream", do_encode_bench_stream)
}

fn decode_benchmarks(byte_sizes: &[usize]) -> ParameterizedBenchmark<usize> {
    ParameterizedBenchmark::new("decode", do_decode_bench, byte_sizes.iter().cloned())
        .warm_up_time(std::time::Duration::from_millis(500))
        .measurement_time(std::time::Duration::from_secs(3))
        .throughput(|s| Throughput::Bytes(*s as u64))
        .with_function("decode_reuse_buf", do_decode_bench_reuse_buf)
        .with_function("decode_slice", do_decode_bench_slice)
        .with_function("decode_stream", do_decode_bench_stream)
}

fn bench(c: &mut Criterion) {
    c.bench("bench_small_input", encode_benchmarks(&BYTE_SIZES[..]));

    c.bench(
        "bench_large_input",
        encode_benchmarks(&LARGE_BYTE_SIZES[..]).sample_size(10),
    );

    c.bench("bench_small_input", decode_benchmarks(&BYTE_SIZES[..]));

    c.bench(
        "bench_large_input",
        decode_benchmarks(&LARGE_BYTE_SIZES[..]).sample_size(10),
    );
}

criterion_group!(benches, bench);
criterion_main!(benches);
<commit_msg>Add benchmark<commit_after>extern crate base64;
#[macro_use]
extern crate criterion;
extern crate rand;

use base64::display;
use base64::{
    decode, decode_config_buf, decode_config_slice, encode, encode_config_buf, encode_config_slice,
    write, Config,
};

use criterion::{black_box, Bencher, Criterion, ParameterizedBenchmark, Throughput};
use rand::{FromEntropy, Rng};
use std::io::{self, Read, Write};

const TEST_CONFIG: Config = base64::STANDARD;

fn do_decode_bench(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    b.iter(|| {
        let orig = decode(&encoded);
        black_box(&orig);
    });
}

fn do_decode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    b.iter(|| {
        decode_config_buf(&encoded, TEST_CONFIG, &mut buf).unwrap();
        black_box(&buf);
        buf.clear();
    });
}

fn do_decode_bench_slice(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    buf.resize(size, 0);
    b.iter(|| {
        decode_config_slice(&encoded, TEST_CONFIG, &mut buf).unwrap();
        black_box(&buf);
    });
}

fn do_decode_bench_stream(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    buf.resize(size, 0);
    buf.truncate(0);

    b.iter(|| {
        let mut cursor = io::Cursor::new(&encoded[..]);
        let mut decoder = base64::read::DecoderReader::new(&mut cursor, TEST_CONFIG);
        decoder.read_to_end(&mut buf).unwrap();
        buf.clear();
        black_box(&buf);
    });
}

fn do_encode_bench(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    b.iter(|| {
        let e = encode(&v);
        black_box(&e);
    });
}

fn do_encode_bench_display(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    b.iter(|| {
        let e = format!("{}", display::Base64Display::with_config(&v, TEST_CONFIG));
        black_box(&e);
    });
}

fn do_encode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = String::new();
    b.iter(|| {
        encode_config_buf(&v, TEST_CONFIG, &mut buf);
        buf.clear();
    });
}

fn do_encode_bench_slice(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = Vec::new();
    // conservative estimate of encoded size
    buf.resize(v.len() * 2, 0);
    b.iter(|| {
        encode_config_slice(&v, TEST_CONFIG, &mut buf);
    });
}

fn do_encode_bench_stream(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let mut buf = Vec::new();

    buf.reserve(size * 2);
    b.iter(|| {
        buf.clear();
        let mut stream_enc = write::EncoderWriter::new(&mut buf, TEST_CONFIG);
        stream_enc.write_all(&v).unwrap();
        stream_enc.flush().unwrap();
    });
}

fn do_encode_bench_string_stream(b: &mut Bencher, &size: &usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);

    b.iter(|| {
        let mut stream_enc = write::EncoderStringWriter::new(TEST_CONFIG);
        stream_enc.write_all(&v).unwrap();
        stream_enc.flush().unwrap();
        let _ = stream_enc.finish().unwrap();
    });
}

fn fill(v: &mut Vec<u8>) {
    let cap = v.capacity();
    // weak randomness is plenty; we just want to not be completely friendly to the branch predictor
    let mut r = rand::rngs::SmallRng::from_entropy();
    while v.len() < cap {
        v.push(r.gen::<u8>());
    }
}

const BYTE_SIZES: [usize; 5] = [3, 50, 100, 500, 3 * 1024];

// Benchmarks over these byte sizes take longer so we will run fewer samples to
// keep the benchmark runtime reasonable.
const LARGE_BYTE_SIZES: [usize; 3] = [3 * 1024 * 1024, 10 * 1024 * 1024, 30 * 1024 * 1024];

fn encode_benchmarks(byte_sizes: &[usize]) -> ParameterizedBenchmark<usize> {
    ParameterizedBenchmark::new("encode", do_encode_bench, byte_sizes.iter().cloned())
        .warm_up_time(std::time::Duration::from_millis(500))
        .measurement_time(std::time::Duration::from_secs(3))
        .throughput(|s| Throughput::Bytes(*s as u64))
        .with_function("encode_display", do_encode_bench_display)
        .with_function("encode_reuse_buf", do_encode_bench_reuse_buf)
        .with_function("encode_slice", do_encode_bench_slice)
        .with_function("encode_reuse_buf_stream", do_encode_bench_stream)
        .with_function("encode_string_stream", do_encode_bench_string_stream)
}

fn decode_benchmarks(byte_sizes: &[usize]) -> ParameterizedBenchmark<usize> {
    ParameterizedBenchmark::new("decode", do_decode_bench, byte_sizes.iter().cloned())
        .warm_up_time(std::time::Duration::from_millis(500))
        .measurement_time(std::time::Duration::from_secs(3))
        .throughput(|s| Throughput::Bytes(*s as u64))
        .with_function("decode_reuse_buf", do_decode_bench_reuse_buf)
        .with_function("decode_slice", do_decode_bench_slice)
        .with_function("decode_stream", do_decode_bench_stream)
}

fn bench(c: &mut Criterion) {
    c.bench("bench_small_input", encode_benchmarks(&BYTE_SIZES[..]));

    c.bench(
        "bench_large_input",
        encode_benchmarks(&LARGE_BYTE_SIZES[..]).sample_size(10),
    );

    c.bench("bench_small_input", decode_benchmarks(&BYTE_SIZES[..]));

    c.bench(
        "bench_large_input",
        decode_benchmarks(&LARGE_BYTE_SIZES[..]).sample_size(10),
    );
}

criterion_group!(benches, bench);
criterion_main!(benches);
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

use crate::ir::attrs::BaseAttrsNode;
use crate::ir::PrimExpr;
use crate::runtime::array::Array;
use crate::runtime::DataType;
use crate::runtime::String as TString;
use tvm_macros::Object;

type IndexExpr = PrimExpr;

#[repr(C)]
#[derive(Object)]
#[ref_name = "Conv2DAttrs"]
#[type_key = "relay.attrs.Conv2DAttrs"]
pub struct Conv2DAttrsNode {
    pub base: BaseAttrsNode,
    pub strides: Array<IndexExpr>,
    pub padding: Array<IndexExpr>,
    pub dilation: Array<IndexExpr>,
    // TODO(@gussmith23) groups is "int", what should it be here?
    pub groups: i32,
    pub channels: IndexExpr,
    pub kernel_size: Array<IndexExpr>,
    pub data_layout: TString,
    pub kernel_layout: TString,
    pub out_layout: TString,
    pub out_dtype: DataType,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "BiasAddAttrs"]
#[type_key = "relay.attrs.BiasAddAttrs"]
pub struct BiasAddAttrsNode {
    pub base: BaseAttrsNode,
    pub axis: i32,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "DenseAttrs"]
#[type_key = "relay.attrs.DenseAttrs"]
pub struct DenseAttrsNode {
    pub base: BaseAttrsNode,
    pub units: IndexExpr,
    pub out_dtype: DataType,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "GlobalPool2DAttrs"]
#[type_key = "relay.attrs.GlobalPool2DAttrs"]
pub struct GlobalPool2DAttrsNode {
    pub base: BaseAttrsNode,
    pub layout: TString,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "MaxPool2DAttrs"]
#[type_key = "relay.attrs.MaxPool2DAttrs"]
pub struct MaxPool2DAttrsNode {
    pub base: BaseAttrsNode,
    pub pool_size: Array<IndexExpr>,
    pub strides: Array<IndexExpr>,
    pub padding: Array<IndexExpr>,
    pub layout: TString,
    pub ceil_mode: bool,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "SoftmaxAttrs"]
#[type_key = "relay.attrs.SoftmaxAttrs"]
pub struct SoftmaxAttrsNode {
    pub base: BaseAttrsNode,
    pub axis: i32,
}
<commit_msg>Add BatchNormAttrs Rust bindings (#6678)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

use crate::ir::attrs::BaseAttrsNode;
use crate::ir::PrimExpr;
use crate::runtime::array::Array;
use crate::runtime::DataType;
use crate::runtime::String as TString;
use tvm_macros::Object;

type IndexExpr = PrimExpr;

#[repr(C)]
#[derive(Object)]
#[ref_name = "Conv2DAttrs"]
#[type_key = "relay.attrs.Conv2DAttrs"]
pub struct Conv2DAttrsNode {
    pub base: BaseAttrsNode,
    pub strides: Array<IndexExpr>,
    pub padding: Array<IndexExpr>,
    pub dilation: Array<IndexExpr>,
    // TODO(@gussmith23) groups is "int", what should it be here?
    pub groups: i32,
    pub channels: IndexExpr,
    pub kernel_size: Array<IndexExpr>,
    pub data_layout: TString,
    pub kernel_layout: TString,
    pub out_layout: TString,
    pub out_dtype: DataType,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "BiasAddAttrs"]
#[type_key = "relay.attrs.BiasAddAttrs"]
pub struct BiasAddAttrsNode {
    pub base: BaseAttrsNode,
    pub axis: i32,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "DenseAttrs"]
#[type_key = "relay.attrs.DenseAttrs"]
pub struct DenseAttrsNode {
    pub base: BaseAttrsNode,
    pub units: IndexExpr,
    pub out_dtype: DataType,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "GlobalPool2DAttrs"]
#[type_key = "relay.attrs.GlobalPool2DAttrs"]
pub struct GlobalPool2DAttrsNode {
    pub base: BaseAttrsNode,
    pub layout: TString,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "MaxPool2DAttrs"]
#[type_key = "relay.attrs.MaxPool2DAttrs"]
pub struct MaxPool2DAttrsNode {
    pub base: BaseAttrsNode,
    pub pool_size: Array<IndexExpr>,
    pub strides: Array<IndexExpr>,
    pub padding: Array<IndexExpr>,
    pub layout: TString,
    pub ceil_mode: bool,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "SoftmaxAttrs"]
#[type_key = "relay.attrs.SoftmaxAttrs"]
pub struct SoftmaxAttrsNode {
    pub base: BaseAttrsNode,
    pub axis: i32,
}

#[repr(C)]
#[derive(Object)]
#[ref_name = "BatchNormAttrs"]
#[type_key = "relay.attrs.BatchNormAttrs"]
pub struct BatchNormAttrsNode {
    pub base: BaseAttrsNode,
    pub axis: i32,
    pub epsilon: f64,
    pub center: bool,
    pub scale: bool,
}
<|endoftext|>


<commit_before>use indexmap::IndexMap;
use serde::{de, ser};
use serde::ser::SerializeMap;

use std::fmt;

use {GraphQLError, Value};
use ast::InputValue;
use executor::ExecutionError;
use parser::{ParseError, SourcePosition, Spanning};
use validation::RuleError;

impl ser::Serialize for ExecutionError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(4))?;

        map.serialize_key("message")?;
        map.serialize_value(self.error().message())?;

        let locations = vec![self.location()];
        map.serialize_key("locations")?;
        map.serialize_value(&locations)?;

        map.serialize_key("path")?;
        map.serialize_value(self.path())?;

        if !self.error().data().is_null() {
            map.serialize_key("data")?;
            map.serialize_value(self.error().data())?;
        }

        map.end()
    }
}

impl<'a> ser::Serialize for GraphQLError<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
            GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
            GraphQLError::NoOperationProvided => {
                serializer.serialize_str("Must provide an operation")
            }
            GraphQLError::MultipleOperationsProvided => serializer
                .serialize_str("Must provide operation name if query contains multiple operations"),
            GraphQLError::UnknownOperationName => serializer.serialize_str("Unknown operation"),
        }
    }
}

impl<'de> de::Deserialize<'de> for InputValue {
    fn deserialize<D>(deserializer: D) -> Result<InputValue, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        struct InputValueVisitor;

        impl<'de> de::Visitor<'de> for InputValueVisitor {
            type Value = InputValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid input value")
            }

            fn visit_bool<E>(self, value: bool) -> Result<InputValue, E> {
                Ok(InputValue::boolean(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                if value >= i64::from(i32::min_value()) && value <= i64::from(i32::max_value()) {
                    Ok(InputValue::int(value as i32))
                } else {
                    Err(E::custom(format!("integer out of range")))
                }
            }

            fn visit_u64<E>(self, value: u64) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                if value <= i32::max_value() as u64 {
                    self.visit_i64(value as i64)
                } else {
                    Err(E::custom(format!("integer out of range")))
                }
            }

            fn visit_f64<E>(self, value: f64) -> Result<InputValue, E> {
                Ok(InputValue::float(value))
            }

            fn visit_str<E>(self, value: &str) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                self.visit_string(value.into())
            }

            fn visit_string<E>(self, value: String) -> Result<InputValue, E> {
                Ok(InputValue::string(value))
            }

            fn visit_none<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_unit<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_seq<V>(self, mut visitor: V) -> Result<InputValue, V::Error>
            where
                V: de::SeqAccess<'de>,
            {
                let mut values = Vec::new();

                while let Some(el) = visitor.next_element()? {
                    values.push(el);
                }

                Ok(InputValue::list(values))
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<InputValue, V::Error>
            where
                V: de::MapAccess<'de>,
            {
                let mut values: IndexMap<String, InputValue> = IndexMap::new();

                while let Some((key, value)) = visitor.next_entry()? {
                    values.insert(key, value);
                }

                Ok(InputValue::object(values))
            }
        }

        deserializer.deserialize_any(InputValueVisitor)
    }
}

impl ser::Serialize for InputValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            InputValue::Null | InputValue::Variable(_) => serializer.serialize_unit(),
            InputValue::Int(v) => serializer.serialize_i64(i64::from(v)),
            InputValue::Float(v) => serializer.serialize_f64(v),
            InputValue::String(ref v) | InputValue::Enum(ref v) => serializer.serialize_str(v),
            InputValue::Boolean(v) => serializer.serialize_bool(v),
            InputValue::List(ref v) => v.iter()
                .map(|x| x.item.clone())
                .collect::<Vec<_>>()
                .serialize(serializer),
            InputValue::Object(ref v) => v.iter()
                .map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
                .collect::<IndexMap<_, _>>()
                .serialize(serializer),
        }
    }
}

impl ser::Serialize for RuleError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        map.serialize_key("message")?;
        map.serialize_value(self.message())?;

        map.serialize_key("locations")?;
        map.serialize_value(self.locations())?;

        map.end()
    }
}

impl ser::Serialize for SourcePosition {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        let line = self.line() + 1;
        map.serialize_key("line")?;
        map.serialize_value(&line)?;

        let column = self.column() + 1;
        map.serialize_key("column")?;
        map.serialize_value(&column)?;

        map.end()
    }
}

impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        let message = format!("{}", self.item);
        map.serialize_key("message")?;
        map.serialize_value(&message)?;

        let mut location = IndexMap::new();
        location.insert("line".to_owned(), self.start.line() + 1);
        location.insert("column".to_owned(), self.start.column() + 1);

        let locations = vec![location];

        map.serialize_key("locations")?;
        map.serialize_value(&locations)?;

        map.end()
    }
}

impl ser::Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            Value::Null => serializer.serialize_unit(),
            Value::Int(v) => serializer.serialize_i64(i64::from(v)),
            Value::Float(v) => serializer.serialize_f64(v),
            Value::String(ref v) => serializer.serialize_str(v),
            Value::Boolean(v) => serializer.serialize_bool(v),
            Value::List(ref v) => v.serialize(serializer),
            Value::Object(ref v) => v.serialize(serializer),
        }
    }
}
<commit_msg>Remove unnecessary `format!()`<commit_after>use indexmap::IndexMap;
use serde::{de, ser};
use serde::ser::SerializeMap;

use std::fmt;

use {GraphQLError, Value};
use ast::InputValue;
use executor::ExecutionError;
use parser::{ParseError, SourcePosition, Spanning};
use validation::RuleError;

impl ser::Serialize for ExecutionError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(4))?;

        map.serialize_key("message")?;
        map.serialize_value(self.error().message())?;

        let locations = vec![self.location()];
        map.serialize_key("locations")?;
        map.serialize_value(&locations)?;

        map.serialize_key("path")?;
        map.serialize_value(self.path())?;

        if !self.error().data().is_null() {
            map.serialize_key("data")?;
            map.serialize_value(self.error().data())?;
        }

        map.end()
    }
}

impl<'a> ser::Serialize for GraphQLError<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
            GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
            GraphQLError::NoOperationProvided => {
                serializer.serialize_str("Must provide an operation")
            }
            GraphQLError::MultipleOperationsProvided => serializer
                .serialize_str("Must provide operation name if query contains multiple operations"),
            GraphQLError::UnknownOperationName => serializer.serialize_str("Unknown operation"),
        }
    }
}

impl<'de> de::Deserialize<'de> for InputValue {
    fn deserialize<D>(deserializer: D) -> Result<InputValue, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        struct InputValueVisitor;

        impl<'de> de::Visitor<'de> for InputValueVisitor {
            type Value = InputValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid input value")
            }

            fn visit_bool<E>(self, value: bool) -> Result<InputValue, E> {
                Ok(InputValue::boolean(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                if value >= i64::from(i32::min_value()) && value <= i64::from(i32::max_value()) {
                    Ok(InputValue::int(value as i32))
                } else {
                    Err(E::custom("integer out of range"))
                }
            }

            fn visit_u64<E>(self, value: u64) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                if value <= i32::max_value() as u64 {
                    self.visit_i64(value as i64)
                } else {
                    Err(E::custom("integer out of range"))
                }
            }

            fn visit_f64<E>(self, value: f64) -> Result<InputValue, E> {
                Ok(InputValue::float(value))
            }

            fn visit_str<E>(self, value: &str) -> Result<InputValue, E>
            where
                E: de::Error,
            {
                self.visit_string(value.into())
            }

            fn visit_string<E>(self, value: String) -> Result<InputValue, E> {
                Ok(InputValue::string(value))
            }

            fn visit_none<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_unit<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_seq<V>(self, mut visitor: V) -> Result<InputValue, V::Error>
            where
                V: de::SeqAccess<'de>,
            {
                let mut values = Vec::new();

                while let Some(el) = visitor.next_element()? {
                    values.push(el);
                }

                Ok(InputValue::list(values))
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<InputValue, V::Error>
            where
                V: de::MapAccess<'de>,
            {
                let mut values: IndexMap<String, InputValue> = IndexMap::new();

                while let Some((key, value)) = visitor.next_entry()? {
                    values.insert(key, value);
                }

                Ok(InputValue::object(values))
            }
        }

        deserializer.deserialize_any(InputValueVisitor)
    }
}

impl ser::Serialize for InputValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            InputValue::Null | InputValue::Variable(_) => serializer.serialize_unit(),
            InputValue::Int(v) => serializer.serialize_i64(i64::from(v)),
            InputValue::Float(v) => serializer.serialize_f64(v),
            InputValue::String(ref v) | InputValue::Enum(ref v) => serializer.serialize_str(v),
            InputValue::Boolean(v) => serializer.serialize_bool(v),
            InputValue::List(ref v) => v.iter()
                .map(|x| x.item.clone())
                .collect::<Vec<_>>()
                .serialize(serializer),
            InputValue::Object(ref v) => v.iter()
                .map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
                .collect::<IndexMap<_, _>>()
                .serialize(serializer),
        }
    }
}

impl ser::Serialize for RuleError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        map.serialize_key("message")?;
        map.serialize_value(self.message())?;

        map.serialize_key("locations")?;
        map.serialize_value(self.locations())?;

        map.end()
    }
}

impl ser::Serialize for SourcePosition {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        let line = self.line() + 1;
        map.serialize_key("line")?;
        map.serialize_value(&line)?;

        let column = self.column() + 1;
        map.serialize_key("column")?;
        map.serialize_value(&column)?;

        map.end()
    }
}

impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        let mut map = serializer.serialize_map(Some(2))?;

        let message = format!("{}", self.item);
        map.serialize_key("message")?;
        map.serialize_value(&message)?;

        let mut location = IndexMap::new();
        location.insert("line".to_owned(), self.start.line() + 1);
        location.insert("column".to_owned(), self.start.column() + 1);

        let locations = vec![location];

        map.serialize_key("locations")?;
        map.serialize_value(&locations)?;

        map.end()
    }
}

impl ser::Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match *self {
            Value::Null => serializer.serialize_unit(),
            Value::Int(v) => serializer.serialize_i64(i64::from(v)),
            Value::Float(v) => serializer.serialize_f64(v),
            Value::String(ref v) => serializer.serialize_str(v),
            Value::Boolean(v) => serializer.serialize_bool(v),
            Value::List(ref v) => v.serialize(serializer),
            Value::Object(ref v) => v.serialize(serializer),
        }
    }
}
<|endoftext|>


<commit_before>use system::SystemData;
use system::Registers;

// Returns clock system_data.cycle passed during opcode
pub fn parse_opcode(system_data: &mut SystemData, registers: &mut Registers)
{

    system_data.cycles = 0;
    let opcode: u8 = system_data.mem_map[registers.program_counter as usize];
    println!("{:x}", opcode);

    //inc
    if (opcode & 0xC7) == 0x04
    {
        system_data.cycles = 1;
        if (opcode & 0x38) == 0x38{
            registers.accumulator += 1;
            registers.program_counter += 1;
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }
    }
    //8bit ld group
    //ld r, n
    else if (opcode & 0xC7) == 0x06
    {
        system_data.cycles = 2;

        if(opcode & 0x38) == 0x38
        {
            registers.accumulator = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x08
        {
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x18
        {
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x28
        {
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }
        registers.program_counter += 2;
    }
    //ld (FF00+C), A
    else if opcode == 0xE2
    {
        system_data.cycles = 2;
        system_data.mem_map[(0xFF00 + registers.c_register) as usize] = registers.accumulator;
        registers.program_counter += 1;
    }
    //16 bit ld group
    else if (opcode & 0xCF) == 0x01
    {
        system_data.cycles = 2;

        if (opcode & 0x30) == 0x30
        {
            registers.stack_pointer = system_data.mem_map[(registers.program_counter + 1) as usize] as u16 | (system_data.mem_map[(registers.program_counter + 2) as usize] as u16) << 8;
        }
        else if (opcode & 0x30) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }

        registers.program_counter += 3;
    }
    //xor
    else if (opcode & 0xF8) == 0xA8
    {
        if (opcode & 0x07) == 0x07
        {
            registers.accumulator = registers.accumulator ^ registers.accumulator;
            registers.program_counter += 1;
            system_data.cycles = 1;
            registers.flags = 0x00;
            if  registers.accumulator ==  0 {
                registers.flags = registers.flags | 0x80;
            }
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else if (opcode == 0x20)
    {
        if (registers.flags & 0x80) != 0x80 {
            system_data.cycles = 3;
            let pc_dest: i8 = (system_data.mem_map[(registers.program_counter + 1) as usize] + 2) as i8;
            registers.program_counter = (registers.program_counter as i32 + pc_dest as i32) as u16;
        }
        else {
            system_data.cycles = 2;
            registers.program_counter += 2;
        }
    }

    //LDD (HL), A - 32
    else if (opcode == 0x32)
    {
        let mut mem_loc: u16 = registers.l_register as u16 | (registers.h_register as u16) << 8;
        system_data.mem_map[mem_loc as usize] = registers.accumulator;
        mem_loc -= 1;
        registers.l_register = (mem_loc & 0x0F) as u8;
        registers.h_register = ((mem_loc & 0xF0) >> 8) as u8;
        system_data.cycles = 2;
        registers.program_counter += 1;
    }
    //cb codes
    else if (opcode == 0xCB){
        let opcode_next :u8 = system_data.mem_map[(registers.program_counter + 1) as usize];
        //bit b, r
        if (opcode_next & 0xC0) == 0x40
        {
            system_data.cycles = 2;
            let test_bit: u8 = (opcode_next & 0x38) >> 3;
            if (opcode_next & 0x07) == 0x04
            {
                registers.flags = registers.flags & 0x10;

                if ((registers.h_register >> test_bit) & 0x01) == 0x00
                {
                    registers.flags = registers.flags | 0xA0;
                }
                else
                {
                    registers.flags = registers.flags | 0x20;
                }
            }
            else
            {
                system_data.cycles = 0;
                println!("No Opcode Found");
            }
            registers.program_counter += 2;
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else
    {
        println!("No Opcode Found");
    }
}<commit_msg>abstracted opcode logic from opcode parser<commit_after>use system::SystemData;
use system::Registers;

// Returns clock system_data.cycle passed during opcode
pub fn parse_opcode(system_data_original: &mut SystemData, registers_original: &mut Registers)
{
    //Borrow splitting
    let mut system_data = system_data_original;
    let mut registers = registers_original;

    system_data.cycles = 0;
    let opcode: u8 = system_data.mem_map[registers.program_counter as usize];
    println!("{:x}", opcode);

    //inc
    if (opcode & 0xC7) == 0x04
    {
        increment(&mut system_data, &mut registers, opcode);
    }
    //8bit ld group
    //ld r, n
    else if (opcode & 0xC7) == 0x06
    {
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
    }
    //ld (FF00+C), A
    else if opcode == 0xE2
    {
        load_accumulator_to_io_port_with_c_offset(&mut system_data, &mut registers);
    }
    //16 bit ld group
    else if (opcode & 0xCF) == 0x01
    {
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
    }
    //xor
    else if (opcode & 0xF8) == 0xA8
    {
        xor_register(&mut system_data, &mut registers, opcode);
    }
    //jump nz, dis
    else if (opcode == 0x20)
    {
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
    }

    //LDD (HL), A
    else if (opcode == 0x32)
    {
        load_decrement_hl_register_by_accumulator(&mut system_data, &mut registers);
    }
    //cb codes
    else if (opcode == 0xCB){
        cb_codes(&mut system_data, &mut registers);
    }
    else
    {
        println!("No Opcode Found");
    }
}

fn increment(system_data: &mut SystemData, registers: &mut Registers, opcode: u8)
{
        system_data.cycles = 1;
        if (opcode & 0x38) == 0x38{
            registers.accumulator += 1;
            registers.program_counter += 1;
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }
}

fn load_n_to_8bit_register(system_data: &mut SystemData, registers: &mut Registers, opcode: u8)
{
        system_data.cycles = 2;
        if(opcode & 0x38) == 0x38
        {
            registers.accumulator = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x08
        {
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x18
        {
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x28
        {
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }
        registers.program_counter += 2;
}

fn load_accumulator_to_io_port_with_c_offset(system_data: &mut SystemData, registers: &mut Registers)
{
        system_data.cycles = 2;
        system_data.mem_map[(0xFF00 + registers.c_register) as usize] = registers.accumulator;
        registers.program_counter += 1;
}

fn load_nn_to_16bit_register(system_data: &mut SystemData, registers: &mut Registers, opcode: u8){
    system_data.cycles = 2;

        if (opcode & 0x30) == 0x30
        {
            registers.stack_pointer = system_data.mem_map[(registers.program_counter + 1) as usize] as u16 | (system_data.mem_map[(registers.program_counter + 2) as usize] as u16) << 8;
        }
        else if (opcode & 0x30) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }

        registers.program_counter += 3;
}

fn xor_register(system_data: &mut SystemData, registers: &mut Registers, opcode: u8)
{
        if (opcode & 0x07) == 0x07
        {
            registers.accumulator = registers.accumulator ^ registers.accumulator;
            registers.program_counter += 1;
            system_data.cycles = 1;
            registers.flags = 0x00;
            if  registers.accumulator ==  0 {
                registers.flags = registers.flags | 0x80;
            }
        }
        else
        {
            println!("No Opcode Found");
        }
}

fn jump_displacement_on_nonzero_flag(system_data: &mut SystemData, registers: &mut Registers)
{
        if (registers.flags & 0x80) != 0x80 {
            system_data.cycles = 3;
            let pc_dest: i8 = (system_data.mem_map[(registers.program_counter + 1) as usize] + 2) as i8;
            registers.program_counter = (registers.program_counter as i32 + pc_dest as i32) as u16;
        }
        else {
            system_data.cycles = 2;
            registers.program_counter += 2;
        }
}

fn load_decrement_hl_register_by_accumulator(system_data: &mut SystemData, registers: &mut Registers)
{
    let mut mem_loc: u16 = registers.l_register as u16 | (registers.h_register as u16) << 8;
    system_data.mem_map[mem_loc as usize] = registers.accumulator;
    mem_loc -= 1;
    registers.l_register = (mem_loc & 0x0F) as u8;
    registers.h_register = ((mem_loc & 0xF0) >> 8) as u8;
    system_data.cycles = 2;
    registers.program_counter += 1;
}

fn cb_codes(system_data_original: &mut SystemData, registers_original: &mut Registers)
{
    //Borrow splitting
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let opcode :u8 = system_data.mem_map[(registers.program_counter + 1) as usize];
    //bit b, r
    if (opcode & 0xC0) == 0x40
    {
        system_data.cycles = 2;
        let test_bit: u8 = (opcode & 0x38) >> 3;
        bit_check_register(&mut system_data, &mut registers, opcode, test_bit)
    }
    else
    {
        println!("No Opcode Found");
    }
}

fn bit_check_register(system_data: &mut SystemData, registers: &mut Registers, opcode: u8, test_bit: u8)
{
        if (opcode & 0x07) == 0x04
        {
            registers.flags = registers.flags & 0x10;

            if ((registers.h_register >> test_bit) & 0x01) == 0x00
            {
                registers.flags = registers.flags | 0xA0;
            }
            else
            {
                registers.flags = registers.flags | 0x20;
            }
        }
        else
        {
            system_data.cycles = 0;
            println!("No Opcode Found");
        }
        registers.program_counter += 2;
}<|endoftext|>