<commit_before>use std::cell::Cell;
use std::cell::RefCell;

use aspect_ratio::*;
use attributes::Attribute;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use float_eq_cairo::ApproxEqCairo;
use handle::RsvgHandle;
use length::*;
use node::*;
use parsers::{parse, parse_and_validate, Parse};
use property_bag::{OwnedPropertyBag, PropertyBag};
use state::{self, Overflow};
use viewbox::*;
use viewport::{draw_in_viewport, ClipMode};

pub struct NodeGroup();

impl NodeGroup {
    pub fn new() -> NodeGroup {
        NodeGroup()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);
        node.draw_children(cascaded, draw_ctx, clipping);
        drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
    }
}

pub struct NodeDefs();

impl NodeDefs {
    pub fn new() -> NodeDefs {
        NodeDefs()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }
}

pub struct NodeSwitch();

impl NodeSwitch {
    pub fn new() -> NodeSwitch {
        NodeSwitch()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);

        if let Some(child) = node.children().find(|c| c.get_cond()) {
            drawing_ctx::draw_node_from_stack(
                draw_ctx,
                &CascadedValues::new(cascaded, &child),
                &child,
                clipping,
            );
        }

        drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
    }
}

pub struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<RsvgLength>,
    h: Cell<RsvgLength>,
    vbox: Cell<Option<ViewBox>>,
    pbag: RefCell<Option<OwnedPropertyBag>>,
}

impl NodeSvg {
    pub fn new() -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            x: Cell::new(RsvgLength::parse_str("0", LengthDir::Horizontal).unwrap()),
            y: Cell::new(RsvgLength::parse_str("0", LengthDir::Vertical).unwrap()),
            w: Cell::new(RsvgLength::parse_str("100%", LengthDir::Horizontal).unwrap()),
            h: Cell::new(RsvgLength::parse_str("100%", LengthDir::Vertical).unwrap()),
            vbox: Cell::new(None),
            pbag: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts(&self, node: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = node.get_parent().is_some();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::X => {
                    if is_inner_svg {
                        self.x.set(parse("x", value, LengthDir::Horizontal)?);
                    }
                }

                Attribute::Y => {
                    if is_inner_svg {
                        self.y.set(parse("y", value, LengthDir::Vertical)?);
                    }
                }

                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        *self.pbag.borrow_mut() = Some(pbag.to_owned());

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        let nx = self.x.get().normalize(values, draw_ctx);
        let ny = self.y.get().normalize(values, draw_ctx);
        let nw = self.w.get().normalize(values, draw_ctx);
        let nh = self.h.get().normalize(values, draw_ctx);

        let do_clip = !values.is_overflow() && node.get_parent().is_some();

        draw_in_viewport(
            nx,
            ny,
            nw,
            nh,
            ClipMode::ClipToViewport,
            do_clip,
            self.vbox.get(),
            self.preserve_aspect_ratio.get(),
            node,
            values,
            drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
            draw_ctx,
            clipping,
            || {
                // we don't push a layer because draw_in_viewport() already does it
                node.draw_children(cascaded, draw_ctx, clipping);
            },
        );
    }
}

pub struct NodeUse {
    link: RefCell<Option<String>>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<Option<RsvgLength>>,
    h: Cell<Option<RsvgLength>>,
}

impl NodeUse {
    pub fn new() -> NodeUse {
        NodeUse {
            link: RefCell::new(None),
            x: Cell::new(RsvgLength::default()),
            y: Cell::new(RsvgLength::default()),
            w: Cell::new(None),
            h: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeUse {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),

                Attribute::Width => self.w.set(
                    parse_and_validate(
                        "width",
                        value,
                        LengthDir::Horizontal,
                        RsvgLength::check_nonnegative,
                    ).map(Some)?,
                ),
                Attribute::Height => self.h.set(
                    parse_and_validate(
                        "height",
                        value,
                        LengthDir::Vertical,
                        RsvgLength::check_nonnegative,
                    ).map(Some)?,
                ),

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        let link = self.link.borrow();

        if link.is_none() {
            return;
        }

        let child = if let Some(acquired) =
            drawing_ctx::get_acquired_node(draw_ctx, link.as_ref().unwrap())
        {
            acquired.get()
        } else {
            return;
        };

        if Node::is_ancestor(node.clone(), child.clone()) {
            // or, if we're <use>'ing ourselves
            return;
        }

        let nx = self.x.get().normalize(values, draw_ctx);
        let ny = self.y.get().normalize(values, draw_ctx);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .get()
            .unwrap_or_else(|| RsvgLength::parse_str("100%", LengthDir::Horizontal).unwrap())
            .normalize(values, draw_ctx);
        let nh = self
            .h
            .get()
            .unwrap_or_else(|| RsvgLength::parse_str("100%", LengthDir::Vertical).unwrap())
            .normalize(values, draw_ctx);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(&0.0) || nh.approx_eq_cairo(&0.0) {
            return;
        }

        if child.get_type() != NodeType::Symbol {
            let cr = drawing_ctx::get_cairo_context(draw_ctx);
            cr.translate(nx, ny);

            drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);

            drawing_ctx::draw_node_from_stack(
                draw_ctx,
                &CascadedValues::new_from_values(&child, values),
                &child,
                clipping,
            );

            drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
        } else {
            child.with_impl(|symbol: &NodeSymbol| {
                let do_clip = !values.is_overflow()
                    || (values.overflow == Overflow::Visible
                        && child.get_specified_values().is_overflow());

                draw_in_viewport(
                    nx,
                    ny,
                    nw,
                    nh,
                    ClipMode::ClipToVbox,
                    do_clip,
                    symbol.vbox.get(),
                    symbol.preserve_aspect_ratio.get(),
                    node,
                    values,
                    drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
                    draw_ctx,
                    clipping,
                    || {
                        // We don't push a layer because draw_in_viewport() already does it
                        child.draw_children(
                            &CascadedValues::new_from_values(&child, values),
                            draw_ctx,
                            clipping,
                        );
                    },
                );
            });
        }
    }
}

pub struct NodeSymbol {
    preserve_aspect_ratio: Cell<AspectRatio>,
    vbox: Cell<Option<ViewBox>>,
}

impl NodeSymbol {
    pub fn new() -> NodeSymbol {
        NodeSymbol {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            vbox: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeSymbol {
    fn set_atts(&self, node: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        // symbol element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        Ok(())
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_size(
    raw_node: *const RsvgNode,
    out_width: *mut RsvgLength,
    out_height: *mut RsvgLength,
) {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    assert!(!out_width.is_null());
    assert!(!out_height.is_null());

    node.with_impl(|svg: &NodeSvg| unsafe {
        *out_width = svg.w.get();
        *out_height = svg.h.get();
    });
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_view_box(raw_node: *const RsvgNode) -> RsvgViewBox {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    let mut vbox: Option<ViewBox> = None;

    node.with_impl(|svg: &NodeSvg| {
        vbox = svg.vbox.get();
    });

    RsvgViewBox::from(vbox)
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_apply_atts(raw_node: *const RsvgNode, handle: *const RsvgHandle) {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    node.with_impl(|svg: &NodeSvg| {
        if let Some(owned_pbag) = svg.pbag.borrow().as_ref() {
            let pbag = PropertyBag::from_owned(owned_pbag);
            state::parse_style_attrs(handle, node, "svg", &pbag);
        }
    });
}
<commit_msg>structure.rs: Use with_discrete_layer()<commit_after>use std::cell::Cell;
use std::cell::RefCell;

use aspect_ratio::*;
use attributes::Attribute;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use float_eq_cairo::ApproxEqCairo;
use handle::RsvgHandle;
use length::*;
use node::*;
use parsers::{parse, parse_and_validate, Parse};
use property_bag::{OwnedPropertyBag, PropertyBag};
use state::{self, Overflow};
use viewbox::*;
use viewport::{draw_in_viewport, ClipMode};

pub struct NodeGroup();

impl NodeGroup {
    pub fn new() -> NodeGroup {
        NodeGroup()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        drawing_ctx::with_discrete_layer(draw_ctx, node, values, clipping, |_cr| {
            node.draw_children(cascaded, draw_ctx, clipping);
        });
    }
}

pub struct NodeDefs();

impl NodeDefs {
    pub fn new() -> NodeDefs {
        NodeDefs()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }
}

pub struct NodeSwitch();

impl NodeSwitch {
    pub fn new() -> NodeSwitch {
        NodeSwitch()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        drawing_ctx::with_discrete_layer(draw_ctx, node, values, clipping, |_cr| {
            if let Some(child) = node.children().find(|c| c.get_cond()) {
                drawing_ctx::draw_node_from_stack(
                    draw_ctx,
                    &CascadedValues::new(cascaded, &child),
                    &child,
                    clipping,
                );
            }
        });
    }
}

pub struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<RsvgLength>,
    h: Cell<RsvgLength>,
    vbox: Cell<Option<ViewBox>>,
    pbag: RefCell<Option<OwnedPropertyBag>>,
}

impl NodeSvg {
    pub fn new() -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            x: Cell::new(RsvgLength::parse_str("0", LengthDir::Horizontal).unwrap()),
            y: Cell::new(RsvgLength::parse_str("0", LengthDir::Vertical).unwrap()),
            w: Cell::new(RsvgLength::parse_str("100%", LengthDir::Horizontal).unwrap()),
            h: Cell::new(RsvgLength::parse_str("100%", LengthDir::Vertical).unwrap()),
            vbox: Cell::new(None),
            pbag: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts(&self, node: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = node.get_parent().is_some();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::X => {
                    if is_inner_svg {
                        self.x.set(parse("x", value, LengthDir::Horizontal)?);
                    }
                }

                Attribute::Y => {
                    if is_inner_svg {
                        self.y.set(parse("y", value, LengthDir::Vertical)?);
                    }
                }

                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        *self.pbag.borrow_mut() = Some(pbag.to_owned());

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        let nx = self.x.get().normalize(values, draw_ctx);
        let ny = self.y.get().normalize(values, draw_ctx);
        let nw = self.w.get().normalize(values, draw_ctx);
        let nh = self.h.get().normalize(values, draw_ctx);

        let do_clip = !values.is_overflow() && node.get_parent().is_some();

        draw_in_viewport(
            nx,
            ny,
            nw,
            nh,
            ClipMode::ClipToViewport,
            do_clip,
            self.vbox.get(),
            self.preserve_aspect_ratio.get(),
            node,
            values,
            drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
            draw_ctx,
            clipping,
            || {
                // we don't push a layer because draw_in_viewport() already does it
                node.draw_children(cascaded, draw_ctx, clipping);
            },
        );
    }
}

pub struct NodeUse {
    link: RefCell<Option<String>>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<Option<RsvgLength>>,
    h: Cell<Option<RsvgLength>>,
}

impl NodeUse {
    pub fn new() -> NodeUse {
        NodeUse {
            link: RefCell::new(None),
            x: Cell::new(RsvgLength::default()),
            y: Cell::new(RsvgLength::default()),
            w: Cell::new(None),
            h: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeUse {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),

                Attribute::Width => self.w.set(
                    parse_and_validate(
                        "width",
                        value,
                        LengthDir::Horizontal,
                        RsvgLength::check_nonnegative,
                    ).map(Some)?,
                ),
                Attribute::Height => self.h.set(
                    parse_and_validate(
                        "height",
                        value,
                        LengthDir::Vertical,
                        RsvgLength::check_nonnegative,
                    ).map(Some)?,
                ),

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        let link = self.link.borrow();

        if link.is_none() {
            return;
        }

        let child = if let Some(acquired) =
            drawing_ctx::get_acquired_node(draw_ctx, link.as_ref().unwrap())
        {
            acquired.get()
        } else {
            return;
        };

        if Node::is_ancestor(node.clone(), child.clone()) {
            // or, if we're <use>'ing ourselves
            return;
        }

        let nx = self.x.get().normalize(values, draw_ctx);
        let ny = self.y.get().normalize(values, draw_ctx);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .get()
            .unwrap_or_else(|| RsvgLength::parse_str("100%", LengthDir::Horizontal).unwrap())
            .normalize(values, draw_ctx);
        let nh = self
            .h
            .get()
            .unwrap_or_else(|| RsvgLength::parse_str("100%", LengthDir::Vertical).unwrap())
            .normalize(values, draw_ctx);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(&0.0) || nh.approx_eq_cairo(&0.0) {
            return;
        }

        if child.get_type() != NodeType::Symbol {
            let cr = drawing_ctx::get_cairo_context(draw_ctx);
            cr.translate(nx, ny);

            drawing_ctx::with_discrete_layer(draw_ctx, node, values, clipping, |_cr| {
                drawing_ctx::draw_node_from_stack(
                    draw_ctx,
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                );
            });
        } else {
            child.with_impl(|symbol: &NodeSymbol| {
                let do_clip = !values.is_overflow()
                    || (values.overflow == Overflow::Visible
                        && child.get_specified_values().is_overflow());

                draw_in_viewport(
                    nx,
                    ny,
                    nw,
                    nh,
                    ClipMode::ClipToVbox,
                    do_clip,
                    symbol.vbox.get(),
                    symbol.preserve_aspect_ratio.get(),
                    node,
                    values,
                    drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
                    draw_ctx,
                    clipping,
                    || {
                        // We don't push a layer because draw_in_viewport() already does it
                        child.draw_children(
                            &CascadedValues::new_from_values(&child, values),
                            draw_ctx,
                            clipping,
                        );
                    },
                );
            });
        }
    }
}

pub struct NodeSymbol {
    preserve_aspect_ratio: Cell<AspectRatio>,
    vbox: Cell<Option<ViewBox>>,
}

impl NodeSymbol {
    pub fn new() -> NodeSymbol {
        NodeSymbol {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            vbox: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeSymbol {
    fn set_atts(&self, node: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        // symbol element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        Ok(())
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_size(
    raw_node: *const RsvgNode,
    out_width: *mut RsvgLength,
    out_height: *mut RsvgLength,
) {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    assert!(!out_width.is_null());
    assert!(!out_height.is_null());

    node.with_impl(|svg: &NodeSvg| unsafe {
        *out_width = svg.w.get();
        *out_height = svg.h.get();
    });
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_view_box(raw_node: *const RsvgNode) -> RsvgViewBox {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    let mut vbox: Option<ViewBox> = None;

    node.with_impl(|svg: &NodeSvg| {
        vbox = svg.vbox.get();
    });

    RsvgViewBox::from(vbox)
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_apply_atts(raw_node: *const RsvgNode, handle: *const RsvgHandle) {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    node.with_impl(|svg: &NodeSvg| {
        if let Some(owned_pbag) = svg.pbag.borrow().as_ref() {
            let pbag = PropertyBag::from_owned(owned_pbag);
            state::parse_style_attrs(handle, node, "svg", &pbag);
        }
    });
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ops::Range;
use std::ptr;
use std::u32;
use smallvec::SmallVec;

use buffer::BufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessFlagBits;
use sync::PipelineStages;

use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that adds a pipeline barrier to a command buffer builder.
///
/// A pipeline barrier is a low-level system-ish command that is often necessary for safety. By
/// default all commands that you add to a command buffer can potentially run simultaneously.
/// Adding a pipeline barrier separates commands before the barrier from commands after the barrier
/// and prevents them from running simultaneously.
///
/// Please take a look at the Vulkan specifications for more information. Pipeline barriers are a
/// complex topic and explaining them in this documentation would be redundant.
///
/// > **Note**: We use a builder-like API here so that users can pass multiple buffers or images of
/// > multiple different types. Doing so with a single function would be very tedious in terms of
/// > API.
pub struct CmdPipelineBarrier<'a> {
    src_stage_mask: vk::PipelineStageFlags,
    dst_stage_mask: vk::PipelineStageFlags,
    dependency_flags: vk::DependencyFlags,
    memory_barriers: SmallVec<[vk::MemoryBarrier; 2]>,
    buffer_barriers: SmallVec<[vk::BufferMemoryBarrier; 8]>,
    image_barriers: SmallVec<[vk::ImageMemoryBarrier; 8]>,
    marker: PhantomData<&'a ()>,
}

impl<'a> CmdPipelineBarrier<'a> {
    /// Creates a new empty pipeline barrier command.
    #[inline]
    pub fn new() -> CmdPipelineBarrier<'a> {
        CmdPipelineBarrier {
            src_stage_mask: 0,
            dst_stage_mask: 0,
            dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
            memory_barriers: SmallVec::new(),
            buffer_barriers: SmallVec::new(),
            image_barriers: SmallVec::new(),
            marker: PhantomData,
        }
    }

    /// Returns true if no barrier or execution dependency has been added yet.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.src_stage_mask == 0 || self.dst_stage_mask == 0
    }

    /// Merges another pipeline builder into this one.
    #[inline]
    pub fn merge(&mut self, other: CmdPipelineBarrier<'a>) {
        self.src_stage_mask |= other.src_stage_mask;
        self.dst_stage_mask |= other.dst_stage_mask;
        self.dependency_flags &= other.dependency_flags;

        self.memory_barriers.extend(other.memory_barriers.into_iter());
        self.buffer_barriers.extend(other.buffer_barriers.into_iter());
        self.image_barriers.extend(other.image_barriers.into_iter());
    }

    /// Adds an execution dependency. This means that all the stages in `source` of the previous
    /// commands must finish before any of the stages in `dest` of the following commands can start.
    ///
    /// # Safety
    ///
    /// - If the pipeline stages include geometry or tessellation stages, then the corresponding
    ///   features must have been enabled in the device.
    /// - There are certain rules regarding the pipeline barriers inside render passes.
    ///
    #[inline]
    pub unsafe fn add_execution_dependency(&mut self, source: PipelineStages, dest: PipelineStages,
                                           by_region: bool)
    {
        if !by_region {
            self.dependency_flags = 0;
        }

        self.src_stage_mask |= source.into();
        self.dst_stage_mask |= dest.into();
    }

    /// Adds a memory barrier. This means that all the memory writes by the given source stages
    /// for the given source accesses must be visible by the given dest stages for the given dest
    /// accesses.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    ///
    pub unsafe fn add_memory_barrier(&mut self, source_stage: PipelineStages,
                                     source_access: AccessFlagBits, dest_stage: PipelineStages,
                                     dest_access: AccessFlagBits, by_region: bool)
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        self.memory_barriers.push(vk::MemoryBarrier {
            sType: vk::STRUCTURE_TYPE_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
        });
    }

    /// Adds a buffer memory barrier. This means that all the memory writes to the given buffer by
    /// the given source stages for the given source accesses must be visible by the given dest
    /// stages for the given dest accesses.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// Also allows transfering buffer ownership between queues.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    /// - The buffer must be alive for at least as long as the command buffer to which this barrier
    ///   is added.
    /// - Queue ownership transfers must be correct.
    ///
    pub unsafe fn add_buffer_memory_barrier<B: ?Sized>
                  (&mut self, buffer: &'a B, source_stage: PipelineStages,
                   source_access: AccessFlagBits, dest_stage: PipelineStages,
                   dest_access: AccessFlagBits, by_region: bool,
                   queue_transfer: Option<(u32, u32)>, offset: usize, size: usize)
        where B: BufferAccess
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        debug_assert!(size <= buffer.size());
        let BufferInner { buffer, offset: org_offset } = buffer.inner();
        let offset = offset + org_offset;

        let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
            (src_queue, dest_queue)
        } else {
            (vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
        };

        self.buffer_barriers.push(vk::BufferMemoryBarrier {
            sType: vk::STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
            srcQueueFamilyIndex: src_queue,
            dstQueueFamilyIndex: dest_queue,
            buffer: buffer.internal_object(),
            offset: offset as vk::DeviceSize,
            size: size as vk::DeviceSize,
        });
    }

    /// Adds an image memory barrier. This is the equivalent of `add_buffer_memory_barrier` but
    /// for images.
    ///
    /// In addition to transfering image ownership between queues, it also allows changing the
    /// layout of images.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    /// - The buffer must be alive for at least as long as the command buffer to which this barrier
    ///   is added.
    /// - Queue ownership transfers must be correct.
    /// - Image layouts transfers must be correct.
    /// - Access flags must be compatible with the image usage flags passed at image creation.
    ///
    pub unsafe fn add_image_memory_barrier<I: ?Sized>(&mut self, image: &'a I, mipmaps: Range<u32>,
                  layers: Range<u32>, source_stage: PipelineStages, source_access: AccessFlagBits,
                  dest_stage: PipelineStages, dest_access: AccessFlagBits, by_region: bool,
                  queue_transfer: Option<(u32, u32)>, current_layout: ImageLayout, new_layout: ImageLayout)
        where I: ImageAccess
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        debug_assert!(mipmaps.start < mipmaps.end);
        // TODO: debug_assert!(mipmaps.end <= image.mipmap_levels());
        debug_assert!(layers.start < layers.end);
        debug_assert!(layers.end <= image.dimensions().array_layers());

        let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
            (src_queue, dest_queue)
        } else {
            (vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
        };

        self.image_barriers.push(vk::ImageMemoryBarrier {
            sType: vk::STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
            oldLayout: current_layout as u32,
            newLayout: new_layout as u32,
            srcQueueFamilyIndex: src_queue,
            dstQueueFamilyIndex: dest_queue,
            image: image.inner().internal_object(),
            subresourceRange: vk::ImageSubresourceRange {
                aspectMask: 1 | 2 | 4 | 8,      // FIXME: wrong
                baseMipLevel: mipmaps.start,
                levelCount: mipmaps.end - mipmaps.start,
                baseArrayLayer: layers.start,
                layerCount: layers.end - layers.start,
            },
        });
    }
}

unsafe impl<'a, P> AddCommand<&'a CmdPipelineBarrier<'a>> for UnsafeCommandBufferBuilder<P>
    where P: CommandPool
{
    type Out = UnsafeCommandBufferBuilder<P>;

    #[inline]
    fn add(self, command: &'a CmdPipelineBarrier<'a>) -> Result<Self::Out, CommandAddError> {
        // If barrier is empty, don't do anything.
        if command.src_stage_mask == 0 || command.dst_stage_mask == 0 {
            debug_assert!(command.src_stage_mask == 0 && command.dst_stage_mask == 0);
            debug_assert!(command.memory_barriers.is_empty());
            debug_assert!(command.buffer_barriers.is_empty());
            debug_assert!(command.image_barriers.is_empty());
            return Ok(self);
        }

        unsafe {
            let vk = self.device().pointers();
            let cmd = self.internal_object();

            vk.CmdPipelineBarrier(cmd, command.src_stage_mask, command.dst_stage_mask,
                                  command.dependency_flags, command.memory_barriers.len() as u32,
                                  command.memory_barriers.as_ptr(),
                                  command.buffer_barriers.len() as u32,
                                  command.buffer_barriers.as_ptr(),
                                  command.image_barriers.len() as u32,
                                  command.image_barriers.as_ptr());
        }

        Ok(self)
    }
}
<commit_msg>Future-proof a dependency on type inference<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ops::Range;
use std::ptr;
use std::u32;
use smallvec::SmallVec;

use buffer::BufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessFlagBits;
use sync::PipelineStages;

use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that adds a pipeline barrier to a command buffer builder.
///
/// A pipeline barrier is a low-level system-ish command that is often necessary for safety. By
/// default all commands that you add to a command buffer can potentially run simultaneously.
/// Adding a pipeline barrier separates commands before the barrier from commands after the barrier
/// and prevents them from running simultaneously.
///
/// Please take a look at the Vulkan specifications for more information. Pipeline barriers are a
/// complex topic and explaining them in this documentation would be redundant.
///
/// > **Note**: We use a builder-like API here so that users can pass multiple buffers or images of
/// > multiple different types. Doing so with a single function would be very tedious in terms of
/// > API.
pub struct CmdPipelineBarrier<'a> {
    src_stage_mask: vk::PipelineStageFlags,
    dst_stage_mask: vk::PipelineStageFlags,
    dependency_flags: vk::DependencyFlags,
    memory_barriers: SmallVec<[vk::MemoryBarrier; 2]>,
    buffer_barriers: SmallVec<[vk::BufferMemoryBarrier; 8]>,
    image_barriers: SmallVec<[vk::ImageMemoryBarrier; 8]>,
    marker: PhantomData<&'a ()>,
}

impl<'a> CmdPipelineBarrier<'a> {
    /// Creates a new empty pipeline barrier command.
    #[inline]
    pub fn new() -> CmdPipelineBarrier<'a> {
        CmdPipelineBarrier {
            src_stage_mask: 0,
            dst_stage_mask: 0,
            dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
            memory_barriers: SmallVec::new(),
            buffer_barriers: SmallVec::new(),
            image_barriers: SmallVec::new(),
            marker: PhantomData,
        }
    }

    /// Returns true if no barrier or execution dependency has been added yet.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.src_stage_mask == 0 || self.dst_stage_mask == 0
    }

    /// Merges another pipeline builder into this one.
    #[inline]
    pub fn merge(&mut self, other: CmdPipelineBarrier<'a>) {
        self.src_stage_mask |= other.src_stage_mask;
        self.dst_stage_mask |= other.dst_stage_mask;
        self.dependency_flags &= other.dependency_flags;

        self.memory_barriers.extend(other.memory_barriers.into_iter());
        self.buffer_barriers.extend(other.buffer_barriers.into_iter());
        self.image_barriers.extend(other.image_barriers.into_iter());
    }

    /// Adds an execution dependency. This means that all the stages in `source` of the previous
    /// commands must finish before any of the stages in `dest` of the following commands can start.
    ///
    /// # Safety
    ///
    /// - If the pipeline stages include geometry or tessellation stages, then the corresponding
    ///   features must have been enabled in the device.
    /// - There are certain rules regarding the pipeline barriers inside render passes.
    ///
    #[inline]
    pub unsafe fn add_execution_dependency(&mut self, source: PipelineStages, dest: PipelineStages,
                                           by_region: bool)
    {
        if !by_region {
            self.dependency_flags = 0;
        }

        self.src_stage_mask |= Into::<vk::PipelineStageFlags>::into(source);
        self.dst_stage_mask |= Into::<vk::PipelineStageFlags>::into(dest);
    }

    /// Adds a memory barrier. This means that all the memory writes by the given source stages
    /// for the given source accesses must be visible by the given dest stages for the given dest
    /// accesses.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    ///
    pub unsafe fn add_memory_barrier(&mut self, source_stage: PipelineStages,
                                     source_access: AccessFlagBits, dest_stage: PipelineStages,
                                     dest_access: AccessFlagBits, by_region: bool)
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        self.memory_barriers.push(vk::MemoryBarrier {
            sType: vk::STRUCTURE_TYPE_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
        });
    }

    /// Adds a buffer memory barrier. This means that all the memory writes to the given buffer by
    /// the given source stages for the given source accesses must be visible by the given dest
    /// stages for the given dest accesses.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// Also allows transfering buffer ownership between queues.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    /// - The buffer must be alive for at least as long as the command buffer to which this barrier
    ///   is added.
    /// - Queue ownership transfers must be correct.
    ///
    pub unsafe fn add_buffer_memory_barrier<B: ?Sized>
                  (&mut self, buffer: &'a B, source_stage: PipelineStages,
                   source_access: AccessFlagBits, dest_stage: PipelineStages,
                   dest_access: AccessFlagBits, by_region: bool,
                   queue_transfer: Option<(u32, u32)>, offset: usize, size: usize)
        where B: BufferAccess
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        debug_assert!(size <= buffer.size());
        let BufferInner { buffer, offset: org_offset } = buffer.inner();
        let offset = offset + org_offset;

        let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
            (src_queue, dest_queue)
        } else {
            (vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
        };

        self.buffer_barriers.push(vk::BufferMemoryBarrier {
            sType: vk::STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
            srcQueueFamilyIndex: src_queue,
            dstQueueFamilyIndex: dest_queue,
            buffer: buffer.internal_object(),
            offset: offset as vk::DeviceSize,
            size: size as vk::DeviceSize,
        });
    }

    /// Adds an image memory barrier. This is the equivalent of `add_buffer_memory_barrier` but
    /// for images.
    ///
    /// In addition to transfering image ownership between queues, it also allows changing the
    /// layout of images.
    ///
    /// Also adds an execution dependency similar to `add_execution_dependency`.
    ///
    /// # Safety
    ///
    /// - Same as `add_execution_dependency`.
    /// - The buffer must be alive for at least as long as the command buffer to which this barrier
    ///   is added.
    /// - Queue ownership transfers must be correct.
    /// - Image layouts transfers must be correct.
    /// - Access flags must be compatible with the image usage flags passed at image creation.
    ///
    pub unsafe fn add_image_memory_barrier<I: ?Sized>(&mut self, image: &'a I, mipmaps: Range<u32>,
                  layers: Range<u32>, source_stage: PipelineStages, source_access: AccessFlagBits,
                  dest_stage: PipelineStages, dest_access: AccessFlagBits, by_region: bool,
                  queue_transfer: Option<(u32, u32)>, current_layout: ImageLayout, new_layout: ImageLayout)
        where I: ImageAccess
    {
        self.add_execution_dependency(source_stage, dest_stage, by_region);

        debug_assert!(mipmaps.start < mipmaps.end);
        // TODO: debug_assert!(mipmaps.end <= image.mipmap_levels());
        debug_assert!(layers.start < layers.end);
        debug_assert!(layers.end <= image.dimensions().array_layers());

        let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
            (src_queue, dest_queue)
        } else {
            (vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
        };

        self.image_barriers.push(vk::ImageMemoryBarrier {
            sType: vk::STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
            pNext: ptr::null(),
            srcAccessMask: source_access.into(),
            dstAccessMask: dest_access.into(),
            oldLayout: current_layout as u32,
            newLayout: new_layout as u32,
            srcQueueFamilyIndex: src_queue,
            dstQueueFamilyIndex: dest_queue,
            image: image.inner().internal_object(),
            subresourceRange: vk::ImageSubresourceRange {
                aspectMask: 1 | 2 | 4 | 8,      // FIXME: wrong
                baseMipLevel: mipmaps.start,
                levelCount: mipmaps.end - mipmaps.start,
                baseArrayLayer: layers.start,
                layerCount: layers.end - layers.start,
            },
        });
    }
}

unsafe impl<'a, P> AddCommand<&'a CmdPipelineBarrier<'a>> for UnsafeCommandBufferBuilder<P>
    where P: CommandPool
{
    type Out = UnsafeCommandBufferBuilder<P>;

    #[inline]
    fn add(self, command: &'a CmdPipelineBarrier<'a>) -> Result<Self::Out, CommandAddError> {
        // If barrier is empty, don't do anything.
        if command.src_stage_mask == 0 || command.dst_stage_mask == 0 {
            debug_assert!(command.src_stage_mask == 0 && command.dst_stage_mask == 0);
            debug_assert!(command.memory_barriers.is_empty());
            debug_assert!(command.buffer_barriers.is_empty());
            debug_assert!(command.image_barriers.is_empty());
            return Ok(self);
        }

        unsafe {
            let vk = self.device().pointers();
            let cmd = self.internal_object();

            vk.CmdPipelineBarrier(cmd, command.src_stage_mask, command.dst_stage_mask,
                                  command.dependency_flags, command.memory_barriers.len() as u32,
                                  command.memory_barriers.as_ptr(),
                                  command.buffer_barriers.len() as u32,
                                  command.buffer_barriers.as_ptr(),
                                  command.image_barriers.len() as u32,
                                  command.image_barriers.as_ptr());
        }

        Ok(self)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate redis_async;
#[macro_use]
extern crate serde_derive;
extern crate dotenv;

use futures::future;
use futures::future::Future;
use std::io;

use actix::prelude::Addr;
use actix_redis::{Command, RedisActor, RespValue};
use actix_web::{middleware, web, App, HttpResponse, HttpServer};
use dotenv::dotenv;
use uuid::Uuid;

#[derive(Serialize, Deserialize)]
pub struct CacheableSecret {
    content: String,
}

#[derive(Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct CreateSecretPostBody {
    content: String,
    expiration_seconds: usize,
}

#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct CreateSecretResponseBody {
    id: Uuid,
}

#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
enum GetSecretResponse {
    Success(CacheableSecret),
    Error(String),
}

#[derive(Debug, Clone, Copy)]
struct AppConfig {
    max_secret_length: usize,
    max_secret_expiration: usize,
}

struct AppState {
    redis: Addr<RedisActor>,
    config: AppConfig,
}

fn create_secret(
    body: web::Json<CreateSecretPostBody>,
    state: web::Data<AppState>,
) -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    let body = body.into_inner();

    let id = Uuid::new_v4();
    let expiration = body.expiration_seconds.to_string();

    let validation = future::result(if body.content.len() > state.config.max_secret_length {
        Err("content too large")
    } else if body.expiration_seconds > state.config.max_secret_expiration {
        Err("expiration too long")
    } else {
        Ok(())
    })
    .map_err(actix_web::error::ErrorBadRequest);

    println!("Writing: {:?}: {:?}", id.to_string(), expiration);

    let write_secret = state
        .redis
        .send(Command(resp_array![
            "SETEX",
            id.to_string(),
            expiration,
            body.content
        ]))
        .map_err(actix_web::Error::from)
        .map(move |_| HttpResponse::Ok().json(CreateSecretResponseBody { id }));

    validation.and_then(|_| write_secret)
}

fn get_secret(
    path: web::Path<String>,
    state: web::Data<AppState>,
) -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    let secret_id = path.to_string();
    println!("Fetching: {:?}", secret_id);

    let fetch_secret = state
        .redis
        .send(Command(resp_array!["GET", secret_id.clone()]))
        .map_err(actix_web::Error::from);

    let expire_secret = state
        .redis
        .send(Command(resp_array!["DEL", secret_id]))
        .map_err(actix_web::Error::from);

    fetch_secret
        .and_then(|result| expire_secret.map(|_| result))
        .map(|res: Result<RespValue, actix_redis::Error>| match res {
            Ok(RespValue::BulkString(bytes)) => {
                let str = String::from_utf8(bytes).expect("non-utf8 string in redis");
                HttpResponse::Ok()
                    .json(GetSecretResponse::Success(CacheableSecret { content: str }))
            }

            Ok(RespValue::Nil) => {
                HttpResponse::NotFound().json(GetSecretResponse::Error("not found".to_string()))
            }

            err => {
                println!("Redis exception: {:?}", err);
                HttpResponse::InternalServerError()
                    .json(GetSecretResponse::Error("something went wrong".to_string()))
            }
        })
}

fn main() -> io::Result<()> {
    env_logger::init();
    dotenv().ok();

    let config = AppConfig {
        max_secret_length: std::env::var("MAX_SECRET_LENGTH")
            .unwrap_or("4096".to_string())
            .parse()
            .expect("unvalid integer value"),
        max_secret_expiration: std::env::var("MAX_SECRET_EXPIRATION")
            .unwrap_or("4096".to_string())
            .parse()
            .expect("unvalid integer value"),
    };
    println!("Booting with config: {:?}", config);

    HttpServer::new(move || {
        let state = AppState {
            redis: RedisActor::start("localhost:6379"),
            config: config,
        };

        App::new()
            .data(state)
            .wrap(middleware::Logger::default())
            .service(web::resource("/secret").route(web::post().to_async(create_secret)))
            .service(web::resource("/secret/{secretid}").route(web::get().to_async(get_secret)))
    })
    .bind("127.0.0.1:8080")?
    .run()
}
<commit_msg>Standardize API response<commit_after>#[macro_use]
extern crate redis_async;
#[macro_use]
extern crate serde_derive;
extern crate dotenv;

use std::io;

use actix::prelude::Addr;
use actix_redis::{Command, RedisActor, RespValue};
use actix_web::{middleware, web, App, HttpResponse, HttpServer};
use dotenv::dotenv;
use futures::future;
use futures::future::Future;
use serde::Serialize;
use uuid::Uuid;

#[derive(Serialize, Deserialize)]
pub struct CacheableSecret {
    content: String,
}

#[derive(Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct CreateSecretPostBody {
    content: String,
    expiration_seconds: usize,
}

#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct CreateSecretResponseBody {
    id: Uuid,
}

#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
enum ApiResponse<T: Serialize> {
    Success(T),
    Error(T),
}

#[derive(Debug, Clone, Copy)]
struct AppConfig {
    max_secret_length: usize,
    max_secret_expiration: usize,
}

struct AppState {
    redis: Addr<RedisActor>,
    config: AppConfig,
}

fn create_secret(
    body: web::Json<CreateSecretPostBody>,
    state: web::Data<AppState>,
) -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    let body = body.into_inner();

    let id = Uuid::new_v4();
    let expiration = body.expiration_seconds.to_string();

    let validation = future::result(if body.content.len() > state.config.max_secret_length {
        Err("content too large")
    } else if body.expiration_seconds > state.config.max_secret_expiration {
        Err("expiration too long")
    } else {
        Ok(())
    })
    .map_err(actix_web::error::ErrorBadRequest);

    println!("Writing: {:?}: {:?}", id.to_string(), expiration);

    let write_secret = state
        .redis
        .send(Command(resp_array![
            "SETEX",
            id.to_string(),
            expiration,
            body.content
        ]))
        .map_err(actix_web::Error::from)
        .map(move |_| {
            HttpResponse::Ok().json(ApiResponse::Success(CreateSecretResponseBody { id }))
        });

    validation.and_then(|_| write_secret)
}

fn get_secret(
    path: web::Path<String>,
    state: web::Data<AppState>,
) -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
    let secret_id = path.to_string();
    println!("Fetching: {:?}", secret_id);

    let fetch_secret = state
        .redis
        .send(Command(resp_array!["GET", secret_id.clone()]))
        .map_err(actix_web::Error::from);

    let expire_secret = state
        .redis
        .send(Command(resp_array!["DEL", secret_id]))
        .map_err(actix_web::Error::from);

    fetch_secret
        .and_then(|result| expire_secret.map(|_| result))
        .map(|res: Result<RespValue, actix_redis::Error>| match res {
            Ok(RespValue::BulkString(bytes)) => {
                let str = String::from_utf8(bytes).expect("non-utf8 string in redis");
                HttpResponse::Ok().json(ApiResponse::Success(CacheableSecret { content: str }))
            }

            Ok(RespValue::Nil) => {
                HttpResponse::NotFound().json(ApiResponse::Error("not found".to_string()))
            }

            err => {
                println!("Redis exception: {:?}", err);
                HttpResponse::InternalServerError()
                    .json(ApiResponse::Error("something went wrong".to_string()))
            }
        })
}

fn main() -> io::Result<()> {
    env_logger::init();
    dotenv().ok();

    let config = AppConfig {
        max_secret_length: std::env::var("MAX_SECRET_LENGTH")
            .unwrap_or("4096".to_string())
            .parse()
            .expect("unvalid integer value"),
        max_secret_expiration: std::env::var("MAX_SECRET_EXPIRATION")
            .unwrap_or("4096".to_string())
            .parse()
            .expect("unvalid integer value"),
    };
    println!("Booting with config: {:?}", config);

    HttpServer::new(move || {
        let state = AppState {
            redis: RedisActor::start("localhost:6379"),
            config: config,
        };

        App::new()
            .data(state)
            .wrap(middleware::Logger::default())
            .service(web::resource("/secret").route(web::post().to_async(create_secret)))
            .service(web::resource("/secret/{secretid}").route(web::get().to_async(get_secret)))
    })
    .bind("127.0.0.1:8080")?
    .run()
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed 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 std::cell::RefCell;
use std::io;
use std::ptr;
use std::rc::{Rc, Weak};
use log::Level;

use super::binary;
use super::client::{Client, ClientChannel};
use super::connection::{Connection, ConnectionId};
use super::ipv4_header::Protocol;
use super::ipv4_packet::Ipv4Packet;
use super::selector::Selector;
use super::tcp_connection::TcpConnection;
use super::udp_connection::UdpConnection;

const TAG: &'static str = "Router";

pub struct Router {
    client: Weak<RefCell<Client>>,
    // there are typically only few connections per client, HashMap would be less efficient
    connections: Vec<Rc<RefCell<Connection>>>,
}

impl Router {
    pub fn new() -> Self {
        Self {
            client: Weak::new(),
            connections: Vec::new(),
        }
    }

    // expose client initialization after construction to break cyclic initialization dependencies
    pub fn set_client(&mut self, client: Weak<RefCell<Client>>) {
        self.client = client;
    }

    pub fn send_to_network(
        &mut self,
        selector: &mut Selector,
        client_channel: &mut ClientChannel,
        ipv4_packet: &Ipv4Packet,
    ) {
        if ipv4_packet.is_valid() {
            match self.connection(selector, ipv4_packet) {
                Ok(index) => {
                    let closed = {
                        let connection_ref = self.connections.get_mut(index).unwrap();
                        let mut connection = connection_ref.borrow_mut();
                        connection.send_to_network(selector, client_channel, ipv4_packet);
                        connection.is_closed()
                    };
                    if closed {
                        // the connection is closed, remove it
                        self.connections.swap_remove(index);
                    }
                }
                Err(err) => error!(target: TAG, "Cannot create route, dropping packet: {}", err),
            }
        } else {
            warn!(target: TAG, "Dropping invalid packet");
            if log_enabled!(target: TAG, Level::Trace) {
                trace!(target: TAG, "{}", binary::to_string(ipv4_packet.raw()));
            }
        }
    }

    fn connection(
        &mut self,
        selector: &mut Selector,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<usize> {
        let (ipv4_header_data, transport_header_data) = ipv4_packet.headers_data();
        let transport_header_data = transport_header_data.expect("No transport");
        let id = ConnectionId::from_headers(ipv4_header_data, transport_header_data);
        let index = match self.find_index(&id) {
            Some(index) => index,
            None => {
                let connection =
                    Self::create_connection(selector, id, self.client.clone(), ipv4_packet)?;
                let index = self.connections.len();
                self.connections.push(connection);
                index
            }
        };
        Ok(index)
    }

    fn create_connection(
        selector: &mut Selector,
        id: ConnectionId,
        client: Weak<RefCell<Client>>,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<Rc<RefCell<Connection>>> {
        let (ipv4_header, transport_header) = ipv4_packet.headers();
        let transport_header = transport_header.expect("No transport");
        match id.protocol() {
            Protocol::Tcp => Ok(TcpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            Protocol::Udp => Ok(UdpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            p => Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Unsupported protocol: {:?}", p),
            )),
        }
    }

    fn find_index(&self, id: &ConnectionId) -> Option<usize> {
        self.connections.iter().position(|connection| {
            connection.borrow().id() == id
        })
    }

    pub fn remove(&mut self, connection: &Connection) {
        let index = self.connections
            .iter()
            .position(|item| {
                // compare pointers to find the connection to remove
                ptr::eq(connection, item.as_ptr())
            })
            .expect("Removing an unknown connection");
        self.connections.swap_remove(index);
    }

    pub fn clear(&mut self, selector: &mut Selector) {
        for connection in &mut self.connections {
            connection.borrow_mut().close(selector);
        }
        self.connections.clear();
    }

    pub fn clean_expired_connections(&mut self, selector: &mut Selector) {
        // remove the last items first, otherwise i might not be less than len() on swap_remove(i)
        for i in (0..self.connections.len()).rev() {
            let expired = {
                let mut connection = self.connections[i].borrow_mut();
                if connection.is_expired() {
                    debug!(
                        target: TAG,
                        "Removed expired connection: {}",
                        connection.id()
                    );
                    connection.close(selector);
                    true
                } else {
                    false
                }
            };
            if expired {
                self.connections.swap_remove(i);
            }
        }
    }
}
<commit_msg>Add debug logs for connection removal<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed 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 std::cell::RefCell;
use std::io;
use std::ptr;
use std::rc::{Rc, Weak};
use log::Level;

use super::binary;
use super::client::{Client, ClientChannel};
use super::connection::{Connection, ConnectionId};
use super::ipv4_header::Protocol;
use super::ipv4_packet::Ipv4Packet;
use super::selector::Selector;
use super::tcp_connection::TcpConnection;
use super::udp_connection::UdpConnection;

const TAG: &'static str = "Router";

pub struct Router {
    client: Weak<RefCell<Client>>,
    // there are typically only few connections per client, HashMap would be less efficient
    connections: Vec<Rc<RefCell<Connection>>>,
}

impl Router {
    pub fn new() -> Self {
        Self {
            client: Weak::new(),
            connections: Vec::new(),
        }
    }

    // expose client initialization after construction to break cyclic initialization dependencies
    pub fn set_client(&mut self, client: Weak<RefCell<Client>>) {
        self.client = client;
    }

    pub fn send_to_network(
        &mut self,
        selector: &mut Selector,
        client_channel: &mut ClientChannel,
        ipv4_packet: &Ipv4Packet,
    ) {
        if ipv4_packet.is_valid() {
            match self.connection(selector, ipv4_packet) {
                Ok(index) => {
                    let closed = {
                        let connection_ref = self.connections.get_mut(index).unwrap();
                        let mut connection = connection_ref.borrow_mut();
                        connection.send_to_network(selector, client_channel, ipv4_packet);
                        if connection.is_closed() {
                            debug!(
                                target: TAG,
                                "Removing connection from router: {}",
                                connection.id()
                            );
                            true
                        } else {
                            false
                        }
                    };
                    if closed {
                        // the connection is closed, remove it
                        self.connections.swap_remove(index);
                    }
                }
                Err(err) => error!(target: TAG, "Cannot create route, dropping packet: {}", err),
            }
        } else {
            warn!(target: TAG, "Dropping invalid packet");
            if log_enabled!(target: TAG, Level::Trace) {
                trace!(target: TAG, "{}", binary::to_string(ipv4_packet.raw()));
            }
        }
    }

    fn connection(
        &mut self,
        selector: &mut Selector,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<usize> {
        let (ipv4_header_data, transport_header_data) = ipv4_packet.headers_data();
        let transport_header_data = transport_header_data.expect("No transport");
        let id = ConnectionId::from_headers(ipv4_header_data, transport_header_data);
        let index = match self.find_index(&id) {
            Some(index) => index,
            None => {
                let connection =
                    Self::create_connection(selector, id, self.client.clone(), ipv4_packet)?;
                let index = self.connections.len();
                self.connections.push(connection);
                index
            }
        };
        Ok(index)
    }

    fn create_connection(
        selector: &mut Selector,
        id: ConnectionId,
        client: Weak<RefCell<Client>>,
        ipv4_packet: &Ipv4Packet,
    ) -> io::Result<Rc<RefCell<Connection>>> {
        let (ipv4_header, transport_header) = ipv4_packet.headers();
        let transport_header = transport_header.expect("No transport");
        match id.protocol() {
            Protocol::Tcp => Ok(TcpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            Protocol::Udp => Ok(UdpConnection::new(
                selector,
                id,
                client,
                ipv4_header,
                transport_header,
            )?),
            p => Err(io::Error::new(
                io::ErrorKind::Other,
                format!("Unsupported protocol: {:?}", p),
            )),
        }
    }

    fn find_index(&self, id: &ConnectionId) -> Option<usize> {
        self.connections.iter().position(|connection| {
            connection.borrow().id() == id
        })
    }

    pub fn remove(&mut self, connection: &Connection) {
        let index = self.connections
            .iter()
            .position(|item| {
                // compare pointers to find the connection to remove
                ptr::eq(connection, item.as_ptr())
            })
            .expect("Removing an unknown connection");
        debug!(
            target: TAG,
            "Self-removing connection from router: {}",
            connection.id()
        );
        self.connections.swap_remove(index);
    }

    pub fn clear(&mut self, selector: &mut Selector) {
        for connection in &mut self.connections {
            connection.borrow_mut().close(selector);
        }
        self.connections.clear();
    }

    pub fn clean_expired_connections(&mut self, selector: &mut Selector) {
        // remove the last items first, otherwise i might not be less than len() on swap_remove(i)
        for i in (0..self.connections.len()).rev() {
            let expired = {
                let mut connection = self.connections[i].borrow_mut();
                if connection.is_expired() {
                    debug!(
                        target: TAG,
                        "Removing expired connection from router: {}",
                        connection.id()
                    );
                    connection.close(selector);
                    true
                } else {
                    false
                }
            };
            if expired {
                self.connections.swap_remove(i);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed 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
//
//    https://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 autocxx_parser::IncludeCppConfig;
use syn::{parse_quote, Ident, Item};

pub(crate) fn create_impl_items(id: &Ident, config: &IncludeCppConfig) -> Vec<Item> {
    if config.exclude_impls {
        return vec![];
    }
    vec![
        Item::Impl(parse_quote! {
            impl UniquePtr<#id> {}
        }),
        Item::Impl(parse_quote! {
            impl CxxVector<#id> {}
        }),
    ]
}
<commit_msg>Add SharedPtr and WeakPtr support.<commit_after>// Copyright 2020 Google LLC
//
// Licensed 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
//
//    https://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 autocxx_parser::IncludeCppConfig;
use syn::{parse_quote, Ident, Item};

pub(crate) fn create_impl_items(id: &Ident, config: &IncludeCppConfig) -> Vec<Item> {
    if config.exclude_impls {
        return vec![];
    }
    vec![
        Item::Impl(parse_quote! {
            impl UniquePtr<#id> {}
        }),
        Item::Impl(parse_quote! {
            impl SharedPtr<#id> {}
        }),
        Item::Impl(parse_quote! {
            impl WeakPtr<#id> {}
        }),
        Item::Impl(parse_quote! {
            impl CxxVector<#id> {}
        }),
    ]
}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                one.krate
            }).collect()
        };

        self.crates.extend(added_crates);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    let mut infos = Vec::new();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                one.krate
            }).collect()
        };

        self.crates.extend(added_crates);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    let mut infos = Vec::new();

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

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

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

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


<commit_before>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 { b/a - 1.0 } else { 1.0 };
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64 * 100.0;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8) {
    let mut best_score = 100.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable = plain.iter().filter( |&c| *c < 10 ).count();

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        // score the remaining possibilities
        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}

#[test]
fn test_score_challenge() {
    assert!( score([11, 42, 50, 101, 49, 45, 36, 49, 101, 49, 45, 32, 101, 53, 36, 55, 49, 60, 101, 44, 54, 101, 47, 48, 40, 53, 44, 43, 34, 79])
           > score([78, 111, 119, 32, 116, 104, 97, 116, 32, 116, 104, 101, 32, 112, 97, 114, 116, 121, 32, 105, 115, 32, 106, 117, 109, 112, 105, 110, 103, 10]) )
}
<commit_msg>Refine unprintable character detection<commit_after>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 { b/a - 1.0 } else { 1.0 };
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64 * 100.0;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8) {
    let mut best_score = 100.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;
    // keep TAB, LF, CR as printable
    let unprintable_chars : [u8, ..30]= [0,1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127];

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable = plain.iter().filter( |&c| unprintable_chars.iter().any(|&v| v == *c) ).count();

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        // score the remaining possibilities
        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}

#[test]
fn test_score_challenge() {
    assert!( score([11, 42, 50, 101, 49, 45, 36, 49, 101, 49, 45, 32, 101, 53, 36, 55, 49, 60, 101, 44, 54, 101, 47, 48, 40, 53, 44, 43, 34, 79])
           > score([78, 111, 119, 32, 116, 104, 97, 116, 32, 116, 104, 101, 32, 112, 97, 114, 116, 121, 32, 105, 115, 32, 106, 117, 109, 112, 105, 110, 103, 10]) )
}
<|endoftext|>