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

use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D};
use gfx::text::glyph::GlyphStore;
use std::sync::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length, LengthPercentage};
use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units};

// `webrender_api::display_item::ItemTag` is private
type ItemTag = (u64, u16);
type HitInfo = Option<ItemTag>;

pub struct DisplayListBuilder {
    current_space_and_clip: wr::SpaceAndClipInfo,
    pub wr: wr::DisplayListBuilder,

    /// Contentful paint, for the purpose of
    /// https://w3c.github.io/paint-timing/#first-contentful-paint
    /// (i.e. the display list contains items of type text,
    /// image, non-white canvas or SVG). Used by metrics.
    pub is_contentful: bool,
}

impl DisplayListBuilder {
    pub fn new(pipeline_id: wr::PipelineId, viewport_size: wr::units::LayoutSize) -> Self {
        Self {
            current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id),
            is_contentful: false,
            wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size),
        }
    }

    fn common_properties(&self, clip_rect: units::LayoutRect) -> wr::CommonItemProperties {
        self.common_properties_with_hit_info(clip_rect, None)
    }

    fn common_properties_with_hit_info(
        &self,
        clip_rect: units::LayoutRect,
        hit_info: HitInfo,
    ) -> wr::CommonItemProperties {
        wr::CommonItemProperties {
            clip_rect,
            clip_id: self.current_space_and_clip.clip_id,
            spatial_id: self.current_space_and_clip.spatial_id,
            hit_info,
            // TODO(gw): Make use of the WR backface visibility functionality.
            flags: wr::PrimitiveFlags::default(),
        }
    }

    fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
        let previous = self.current_space_and_clip;
        let result = f(self);
        self.current_space_and_clip = previous;
        result
    }
}

impl Fragment {
    pub(crate) fn build_display_list(
        &self,
        builder: &mut DisplayListBuilder,
        containing_block: &Rect<Length>,
    ) {
        match self {
            Fragment::Box(b) => b.build_display_list(builder, containing_block),
            Fragment::Anonymous(a) => {
                let rect = a
                    .rect
                    .to_physical(a.mode, containing_block)
                    .translate(&containing_block.top_left);
                for child in &a.children {
                    child.build_display_list(builder, &rect)
                }
            },
            Fragment::Text(t) => {
                builder.is_contentful = true;
                let rect = t
                    .rect
                    .to_physical(t.parent_style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let mut baseline_origin = rect.top_left.clone();
                baseline_origin.y += t.ascent;
                let glyphs = glyphs(&t.glyphs, baseline_origin);
                if glyphs.is_empty() {
                    return;
                }
                let hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
                let common = builder.common_properties_with_hit_info(rect.clone().into(), hit_info);
                let color = t.parent_style.clone_color();
                builder
                    .wr
                    .push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
            },
            Fragment::Image(i) => {
                use style::computed_values::image_rendering::T as ImageRendering;
                builder.is_contentful = true;
                let rect = i
                    .rect
                    .to_physical(i.style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let common = builder.common_properties(rect.clone().into());
                builder.wr.push_image(
                    &common,
                    rect.into(),
                    match i.style.get_inherited_box().image_rendering {
                        ImageRendering::Auto => wr::ImageRendering::Auto,
                        ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
                        ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
                    },
                    wr::AlphaType::PremultipliedAlpha,
                    i.image_key,
                    wr::ColorF::WHITE,
                );
            },
        }
    }
}

impl BoxFragment {
    fn build_display_list(
        &self,
        builder: &mut DisplayListBuilder,
        containing_block: &Rect<Length>,
    ) {
        let border_rect = self
            .border_rect()
            .to_physical(self.style.writing_mode, containing_block)
            .translate(&containing_block.top_left)
            .into();
        let border_radius = self.border_radius(&border_rect);
        let hit_info = hit_info(&self.style, self.tag, Cursor::Default);
        if hit_info.is_some() {
            let common = builder.common_properties_with_hit_info(border_rect, hit_info);
            builder.wr.push_hit_test(&common)
        }

        self.background_display_items(builder, border_rect, &border_radius);
        self.border_display_items(builder, border_rect, border_radius);
        let content_rect = self
            .content_rect
            .to_physical(self.style.writing_mode, containing_block)
            .translate(&containing_block.top_left);
        for child in &self.children {
            child.build_display_list(builder, &content_rect)
        }
    }

    fn border_radius(&self, border_rect: &units::LayoutRect) -> wr::BorderRadius {
        let resolve = |radius: &LengthPercentage, box_size: f32| {
            radius.percentage_relative_to(Length::new(box_size)).px()
        };
        let corner = |corner: &style::values::computed::BorderCornerRadius| {
            Size2D::new(
                resolve(&corner.0.width.0, border_rect.size.width),
                resolve(&corner.0.height.0, border_rect.size.height),
            )
        };
        let b = self.style.get_border();
        wr::BorderRadius {
            top_left: corner(&b.border_top_left_radius),
            top_right: corner(&b.border_top_right_radius),
            bottom_right: corner(&b.border_bottom_right_radius),
            bottom_left: corner(&b.border_bottom_left_radius),
        }
    }

    fn background_display_items(
        &self,
        builder: &mut DisplayListBuilder,
        border_rect: units::LayoutRect,
        border_radius: &wr::BorderRadius,
    ) {
        let background_color = self
            .style
            .resolve_color(self.style.clone_background_color());
        if background_color.alpha > 0 {
            builder.clipping_and_scrolling_scope(|builder| {
                if !border_radius.is_zero() {
                    builder.current_space_and_clip.clip_id = builder.wr.define_clip(
                        &builder.current_space_and_clip,
                        border_rect,
                        Some(wr::ComplexClipRegion {
                            rect: border_rect,
                            radii: *border_radius,
                            mode: wr::ClipMode::Clip,
                        }),
                        None,
                    );
                }
                let common = builder.common_properties(border_rect);
                builder.wr.push_rect(&common, rgba(background_color))
            });
        }
    }

    fn border_display_items(
        &self,
        builder: &mut DisplayListBuilder,
        border_rect: units::LayoutRect,
        radius: wr::BorderRadius,
    ) {
        let b = self.style.get_border();
        let widths = SideOffsets2D::new(
            b.border_top_width.px(),
            b.border_right_width.px(),
            b.border_bottom_width.px(),
            b.border_left_width.px(),
        );
        if widths == SideOffsets2D::zero() {
            return;
        }
        let side = |style, color| wr::BorderSide {
            color: rgba(self.style.resolve_color(color)),
            style: match style {
                BorderStyle::None => wr::BorderStyle::None,
                BorderStyle::Solid => wr::BorderStyle::Solid,
                BorderStyle::Double => wr::BorderStyle::Double,
                BorderStyle::Dotted => wr::BorderStyle::Dotted,
                BorderStyle::Dashed => wr::BorderStyle::Dashed,
                BorderStyle::Hidden => wr::BorderStyle::Hidden,
                BorderStyle::Groove => wr::BorderStyle::Groove,
                BorderStyle::Ridge => wr::BorderStyle::Ridge,
                BorderStyle::Inset => wr::BorderStyle::Inset,
                BorderStyle::Outset => wr::BorderStyle::Outset,
            },
        };
        let common = builder.common_properties(border_rect);
        let details = wr::BorderDetails::Normal(wr::NormalBorder {
            top: side(b.border_top_style, b.border_top_color),
            right: side(b.border_right_style, b.border_right_color),
            bottom: side(b.border_bottom_style, b.border_bottom_color),
            left: side(b.border_left_style, b.border_left_color),
            radius,
            do_aa: true,
        });
        builder
            .wr
            .push_border(&common, border_rect, widths, details)
    }
}

fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
    wr::ColorF::new(
        rgba.red_f32(),
        rgba.green_f32(),
        rgba.blue_f32(),
        rgba.alpha_f32(),
    )
}

fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> {
    use gfx_traits::ByteIndex;
    use range::Range;

    let mut glyphs = vec![];
    for run in glyph_runs {
        for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) {
            if !run.is_whitespace() {
                let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
                let point = units::LayoutPoint::new(
                    origin.x.px() + glyph_offset.x.to_f32_px(),
                    origin.y.px() + glyph_offset.y.to_f32_px(),
                );
                let glyph = wr::GlyphInstance {
                    index: glyph.id(),
                    point,
                };
                glyphs.push(glyph);
            }
            origin.x += Length::from(glyph.advance());
        }
    }
    glyphs
}

fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo {
    use style::computed_values::pointer_events::T as PointerEvents;

    let inherited_ui = style.get_inherited_ui();
    if inherited_ui.pointer_events == PointerEvents::None {
        None
    } else {
        let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor);
        Some((tag.0 as u64, cursor as u16))
    }
}

fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
    match kind {
        CursorKind::Auto => auto_cursor,
        CursorKind::None => Cursor::None,
        CursorKind::Default => Cursor::Default,
        CursorKind::Pointer => Cursor::Pointer,
        CursorKind::ContextMenu => Cursor::ContextMenu,
        CursorKind::Help => Cursor::Help,
        CursorKind::Progress => Cursor::Progress,
        CursorKind::Wait => Cursor::Wait,
        CursorKind::Cell => Cursor::Cell,
        CursorKind::Crosshair => Cursor::Crosshair,
        CursorKind::Text => Cursor::Text,
        CursorKind::VerticalText => Cursor::VerticalText,
        CursorKind::Alias => Cursor::Alias,
        CursorKind::Copy => Cursor::Copy,
        CursorKind::Move => Cursor::Move,
        CursorKind::NoDrop => Cursor::NoDrop,
        CursorKind::NotAllowed => Cursor::NotAllowed,
        CursorKind::Grab => Cursor::Grab,
        CursorKind::Grabbing => Cursor::Grabbing,
        CursorKind::EResize => Cursor::EResize,
        CursorKind::NResize => Cursor::NResize,
        CursorKind::NeResize => Cursor::NeResize,
        CursorKind::NwResize => Cursor::NwResize,
        CursorKind::SResize => Cursor::SResize,
        CursorKind::SeResize => Cursor::SeResize,
        CursorKind::SwResize => Cursor::SwResize,
        CursorKind::WResize => Cursor::WResize,
        CursorKind::EwResize => Cursor::EwResize,
        CursorKind::NsResize => Cursor::NsResize,
        CursorKind::NeswResize => Cursor::NeswResize,
        CursorKind::NwseResize => Cursor::NwseResize,
        CursorKind::ColResize => Cursor::ColResize,
        CursorKind::RowResize => Cursor::RowResize,
        CursorKind::AllScroll => Cursor::AllScroll,
        CursorKind::ZoomIn => Cursor::ZoomIn,
        CursorKind::ZoomOut => Cursor::ZoomOut,
    }
}
<commit_msg>Introduce BuilderForBoxFragment<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D};
use gfx::text::glyph::GlyphStore;
use std::sync::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length, LengthPercentage};
use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units};

// `webrender_api::display_item::ItemTag` is private
type ItemTag = (u64, u16);
type HitInfo = Option<ItemTag>;

pub struct DisplayListBuilder {
    current_space_and_clip: wr::SpaceAndClipInfo,
    pub wr: wr::DisplayListBuilder,

    /// Contentful paint, for the purpose of
    /// https://w3c.github.io/paint-timing/#first-contentful-paint
    /// (i.e. the display list contains items of type text,
    /// image, non-white canvas or SVG). Used by metrics.
    pub is_contentful: bool,
}

impl DisplayListBuilder {
    pub fn new(pipeline_id: wr::PipelineId, viewport_size: wr::units::LayoutSize) -> Self {
        Self {
            current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id),
            is_contentful: false,
            wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size),
        }
    }

    fn common_properties(&self, clip_rect: units::LayoutRect) -> wr::CommonItemProperties {
        self.common_properties_with_hit_info(clip_rect, None)
    }

    fn common_properties_with_hit_info(
        &self,
        clip_rect: units::LayoutRect,
        hit_info: HitInfo,
    ) -> wr::CommonItemProperties {
        wr::CommonItemProperties {
            clip_rect,
            clip_id: self.current_space_and_clip.clip_id,
            spatial_id: self.current_space_and_clip.spatial_id,
            hit_info,
            // TODO(gw): Make use of the WR backface visibility functionality.
            flags: wr::PrimitiveFlags::default(),
        }
    }

    fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
        let previous = self.current_space_and_clip;
        let result = f(self);
        self.current_space_and_clip = previous;
        result
    }
}

impl Fragment {
    pub(crate) fn build_display_list(
        &self,
        builder: &mut DisplayListBuilder,
        containing_block: &Rect<Length>,
    ) {
        match self {
            Fragment::Box(b) => {
                BuilderForBoxFragment::new(b, containing_block).build(builder, containing_block)
            },
            Fragment::Anonymous(a) => {
                let rect = a
                    .rect
                    .to_physical(a.mode, containing_block)
                    .translate(&containing_block.top_left);
                for child in &a.children {
                    child.build_display_list(builder, &rect)
                }
            },
            Fragment::Text(t) => {
                builder.is_contentful = true;
                let rect = t
                    .rect
                    .to_physical(t.parent_style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let mut baseline_origin = rect.top_left.clone();
                baseline_origin.y += t.ascent;
                let glyphs = glyphs(&t.glyphs, baseline_origin);
                if glyphs.is_empty() {
                    return;
                }
                let hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
                let common = builder.common_properties_with_hit_info(rect.clone().into(), hit_info);
                let color = t.parent_style.clone_color();
                builder
                    .wr
                    .push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
            },
            Fragment::Image(i) => {
                use style::computed_values::image_rendering::T as ImageRendering;
                builder.is_contentful = true;
                let rect = i
                    .rect
                    .to_physical(i.style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let common = builder.common_properties(rect.clone().into());
                builder.wr.push_image(
                    &common,
                    rect.into(),
                    match i.style.get_inherited_box().image_rendering {
                        ImageRendering::Auto => wr::ImageRendering::Auto,
                        ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
                        ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
                    },
                    wr::AlphaType::PremultipliedAlpha,
                    i.image_key,
                    wr::ColorF::WHITE,
                );
            },
        }
    }
}

struct BuilderForBoxFragment<'a> {
    fragment: &'a BoxFragment,
    border_rect: units::LayoutRect,
    border_radius: wr::BorderRadius,
}

impl<'a> BuilderForBoxFragment<'a> {
    fn new(fragment: &'a BoxFragment, containing_block: &Rect<Length>) -> Self {
        let border_rect: units::LayoutRect = fragment
            .border_rect()
            .to_physical(fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left)
            .into();

        let border_radius = {
            let resolve = |radius: &LengthPercentage, box_size: f32| {
                radius.percentage_relative_to(Length::new(box_size)).px()
            };
            let corner = |corner: &style::values::computed::BorderCornerRadius| {
                Size2D::new(
                    resolve(&corner.0.width.0, border_rect.size.width),
                    resolve(&corner.0.height.0, border_rect.size.height),
                )
            };
            let b = fragment.style.get_border();
            wr::BorderRadius {
                top_left: corner(&b.border_top_left_radius),
                top_right: corner(&b.border_top_right_radius),
                bottom_right: corner(&b.border_bottom_right_radius),
                bottom_left: corner(&b.border_bottom_left_radius),
            }
        };

        Self {
            fragment,
            border_rect,
            border_radius,
        }
    }

    fn build(&mut self, builder: &mut DisplayListBuilder, containing_block: &Rect<Length>) {
        let hit_info = hit_info(&self.fragment.style, self.fragment.tag, Cursor::Default);
        if hit_info.is_some() {
            let common = builder.common_properties_with_hit_info(self.border_rect, hit_info);
            builder.wr.push_hit_test(&common)
        }

        self.background_display_items(builder);
        self.border_display_items(builder);
        let content_rect = self
            .fragment
            .content_rect
            .to_physical(self.fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left);
        for child in &self.fragment.children {
            child.build_display_list(builder, &content_rect)
        }
    }

    fn background_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let background_color = self
            .fragment
            .style
            .resolve_color(self.fragment.style.clone_background_color());
        if background_color.alpha > 0 {
            builder.clipping_and_scrolling_scope(|builder| {
                if !self.border_radius.is_zero() {
                    builder.current_space_and_clip.clip_id = builder.wr.define_clip(
                        &builder.current_space_and_clip,
                        self.border_rect,
                        Some(wr::ComplexClipRegion {
                            rect: self.border_rect,
                            radii: self.border_radius,
                            mode: wr::ClipMode::Clip,
                        }),
                        None,
                    );
                }
                let common = builder.common_properties(self.border_rect);
                builder.wr.push_rect(&common, rgba(background_color))
            });
        }
    }

    fn border_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let b = self.fragment.style.get_border();
        let widths = SideOffsets2D::new(
            b.border_top_width.px(),
            b.border_right_width.px(),
            b.border_bottom_width.px(),
            b.border_left_width.px(),
        );
        if widths == SideOffsets2D::zero() {
            return;
        }
        let side = |style, color| wr::BorderSide {
            color: rgba(self.fragment.style.resolve_color(color)),
            style: match style {
                BorderStyle::None => wr::BorderStyle::None,
                BorderStyle::Solid => wr::BorderStyle::Solid,
                BorderStyle::Double => wr::BorderStyle::Double,
                BorderStyle::Dotted => wr::BorderStyle::Dotted,
                BorderStyle::Dashed => wr::BorderStyle::Dashed,
                BorderStyle::Hidden => wr::BorderStyle::Hidden,
                BorderStyle::Groove => wr::BorderStyle::Groove,
                BorderStyle::Ridge => wr::BorderStyle::Ridge,
                BorderStyle::Inset => wr::BorderStyle::Inset,
                BorderStyle::Outset => wr::BorderStyle::Outset,
            },
        };
        let common = builder.common_properties(self.border_rect);
        let details = wr::BorderDetails::Normal(wr::NormalBorder {
            top: side(b.border_top_style, b.border_top_color),
            right: side(b.border_right_style, b.border_right_color),
            bottom: side(b.border_bottom_style, b.border_bottom_color),
            left: side(b.border_left_style, b.border_left_color),
            radius: self.border_radius,
            do_aa: true,
        });
        builder
            .wr
            .push_border(&common, self.border_rect, widths, details)
    }
}

fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
    wr::ColorF::new(
        rgba.red_f32(),
        rgba.green_f32(),
        rgba.blue_f32(),
        rgba.alpha_f32(),
    )
}

fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> {
    use gfx_traits::ByteIndex;
    use range::Range;

    let mut glyphs = vec![];
    for run in glyph_runs {
        for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) {
            if !run.is_whitespace() {
                let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
                let point = units::LayoutPoint::new(
                    origin.x.px() + glyph_offset.x.to_f32_px(),
                    origin.y.px() + glyph_offset.y.to_f32_px(),
                );
                let glyph = wr::GlyphInstance {
                    index: glyph.id(),
                    point,
                };
                glyphs.push(glyph);
            }
            origin.x += Length::from(glyph.advance());
        }
    }
    glyphs
}

fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo {
    use style::computed_values::pointer_events::T as PointerEvents;

    let inherited_ui = style.get_inherited_ui();
    if inherited_ui.pointer_events == PointerEvents::None {
        None
    } else {
        let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor);
        Some((tag.0 as u64, cursor as u16))
    }
}

fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
    match kind {
        CursorKind::Auto => auto_cursor,
        CursorKind::None => Cursor::None,
        CursorKind::Default => Cursor::Default,
        CursorKind::Pointer => Cursor::Pointer,
        CursorKind::ContextMenu => Cursor::ContextMenu,
        CursorKind::Help => Cursor::Help,
        CursorKind::Progress => Cursor::Progress,
        CursorKind::Wait => Cursor::Wait,
        CursorKind::Cell => Cursor::Cell,
        CursorKind::Crosshair => Cursor::Crosshair,
        CursorKind::Text => Cursor::Text,
        CursorKind::VerticalText => Cursor::VerticalText,
        CursorKind::Alias => Cursor::Alias,
        CursorKind::Copy => Cursor::Copy,
        CursorKind::Move => Cursor::Move,
        CursorKind::NoDrop => Cursor::NoDrop,
        CursorKind::NotAllowed => Cursor::NotAllowed,
        CursorKind::Grab => Cursor::Grab,
        CursorKind::Grabbing => Cursor::Grabbing,
        CursorKind::EResize => Cursor::EResize,
        CursorKind::NResize => Cursor::NResize,
        CursorKind::NeResize => Cursor::NeResize,
        CursorKind::NwResize => Cursor::NwResize,
        CursorKind::SResize => Cursor::SResize,
        CursorKind::SeResize => Cursor::SeResize,
        CursorKind::SwResize => Cursor::SwResize,
        CursorKind::WResize => Cursor::WResize,
        CursorKind::EwResize => Cursor::EwResize,
        CursorKind::NsResize => Cursor::NsResize,
        CursorKind::NeswResize => Cursor::NeswResize,
        CursorKind::NwseResize => Cursor::NwseResize,
        CursorKind::ColResize => Cursor::ColResize,
        CursorKind::RowResize => Cursor::RowResize,
        CursorKind::AllScroll => Cursor::AllScroll,
        CursorKind::ZoomIn => Cursor::ZoomIn,
        CursorKind::ZoomOut => Cursor::ZoomOut,
    }
}
<|endoftext|>


<commit_before>use super::Chip8;
use std::slice::bytes::copy_memory;

// 0nnn - SYS addr
// Jump to a machine code routine at nnn.
//
// This instruction is only used on the old computers on which Chip-8 was
// originally implemented. It is ignored by modern interpreters.
pub fn jump_to_sys_routine(ch8: &mut Chip8, addr: uint) {
    // Do nothing
}

// 00E0 - CLS
// Clear the display.
pub fn clear_display(ch8: &mut Chip8) {
    for px in ch8.display.mut_iter() {
        *px = 0;
    }
}

// 00EE - RET
// Return from a subroutine.
//
// The interpreter sets the program counter to the address at the top of
// the stack, then subtracts 1 from the stack pointer.
pub fn ret_from_subroutine(ch8: &mut Chip8) {
    ch8.pc = ch8.stack[ch8.sp as uint];
    ch8.sp -= 1;
}

// 1nnn - JP addr
// Jump to location nnn.
//
// The interpreter sets the program counter to nnn.
pub fn jump_addr(ch8: &mut Chip8, addr: u16) {
    ch8.pc = addr;
}

// 2nnn - CALL addr
// Call subroutine at nnn.
//
// The interpreter increments the stack pointer, then puts the current PC
// on the top of the stack. The PC is then set to nnn.
pub fn call_subroutine(ch8: &mut Chip8, addr: uint) {
    ch8.sp += 1;
    ch8.stack[ch8.sp as uint] = ch8.pc;
    ch8.pc = addr as u16;
}

// 3xkk - SE Vx, byte
// Skip next instruction if Vx = kk.
//
// The interpreter compares register Vx to kk, and if they are equal,
// increments the program counter by 2.
pub fn skip_next_vx_eq(ch8: &mut Chip8, x: uint, to: u8) {
    if ch8.v[x] == to {
        ch8.pc += 2;
    }
}

// 4xkk - SNE Vx, byte
// Skip next instruction if Vx != kk.
//
// The interpreter compares register Vx to kk, and if they are not equal,
// increments the program counter by 2.
pub fn skip_next_vx_ne(ch8: &mut Chip8, x: uint, to: u8) {
    if ch8.v[x] != to {
        ch8.pc += 2;
    }
}

// 5xy0 - SE Vx, Vy
// Skip next instruction if Vx = Vy.
//
// The interpreter compares register Vx to register Vy, and if they are
// equal, increments the program counter by 2.
pub fn skip_next_vx_eq_vy(ch8: &mut Chip8, x: uint, y: uint) {
    if ch8.v[x] == ch8.v[y] {
        ch8.pc += 2;
    }
}

// 6xkk - LD Vx, byte
// Set Vx = kk.
//
// The interpreter puts the value kk into register Vx.
pub fn set_vx_byte(ch8: &mut Chip8, x: uint, byte: u8) {
    ch8.v[x] = byte;
}

// 7xkk - ADD Vx, byte
// Set Vx = Vx + kk.
//
// Adds the value kk to the value of register Vx, then stores the
// result in Vx.
pub fn add_vx_byte(ch8: &mut Chip8, x: uint, byte: u8) {
    ch8.v[x] += byte;
}

// 8xy0 - LD Vx, Vy
// Set Vx = Vy.
//
// Stores the value of register Vy in register Vx.
pub fn set_vx_to_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] = ch8.v[y];
}

// 8xy2 - AND Vx, Vy
// Set Vx = Vx AND Vy.
//
// Performs a bitwise AND on the values of Vx and Vy, then stores the
// result in Vx. A bitwise AND compares the corrseponding bits from two
// values, and if both bits are 1, then the same bit in the result is also
// 1. Otherwise, it is 0.
pub fn set_vx_to_vx_and_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] &= ch8.v[y];
}

// 8xy3 - XOR Vx, Vy
// Set Vx = Vx XOR Vy.
//
// Performs a bitwise exclusive OR on the values of Vx and Vy, then stores
// the result in Vx. An exclusive OR compares the corrseponding bits from
// two values, and if the bits are not both the same, then the
// corresponding bit in the result is set to 1. Otherwise, it is 0.
pub fn set_vx_to_vx_xor_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] ^= ch8.v[y];
}

// 8xy4 - ADD Vx, Vy
// Set Vx = Vx + Vy, set VF = carry.
//
// The values of Vx and Vy are added together. If the result is greater than
// 8 bits (i.e., > 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits
// of the result are kept, and stored in Vx.
pub fn add_vx_vy(ch8: &mut Chip8, x: uint, y: uint) {
    let result = (ch8.v[x] + ch8.v[y]) as u16;
    ch8.v[0xF] = (result > 255) as u8;
    ch8.v[x] = result as u8;
}

// 8xy5 - SUB Vx, Vy
// Set Vx = Vx - Vy, set VF = NOT borrow.
//
// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx,
// and the results stored in Vx.
pub fn sub_vx_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[0xF] = (ch8.v[x] > ch8.v[y]) as u8;
    ch8.v[x] -= ch8.v[y];
}

// 8xyE - SHL Vx {, Vy}
// Set Vx = Vx SHL 1.
//
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise
// to 0. Then Vx is multiplied by 2.
pub fn set_vx_to_vx_shl_1(ch8: &mut Chip8, x: uint) {
    // TODO: Is this just a left shift by 1?
    ch8.v[x] <<= 1;
}

pub fn set_i(ch8: &mut Chip8, to: u16) {
    ch8.i = to;
}

pub fn set_vx_rand_and(ch8: &mut Chip8, x: uint, to: u8) {
    use std::rand::{task_rng, Rng};
    let mut rgen = task_rng();
    ch8.v[x] = rgen.gen::<u8>() & to;
}

pub fn display_sprite(ch8: &mut Chip8, vx: uint, vy: uint, n: uint) {
    use super::{ DISPLAY_WIDTH, DISPLAY_HEIGHT };
    let x_off = ch8.v[vx] as uint;
    let y_off = ch8.v[vy] as uint * DISPLAY_WIDTH;
    let offset = x_off + y_off;

    for mut y in range(0u, n) {
        if y >= DISPLAY_HEIGHT {
            y = y - DISPLAY_HEIGHT;
        }
        let b = ch8.ram[ch8.i as uint + y];
        for mut x in range(0u, 8) {
            if x >= DISPLAY_WIDTH {
                x = x - DISPLAY_WIDTH;
            }
            let idx = offset + (y * DISPLAY_WIDTH) + x;
            if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                ch8.display[idx] ^= b & (0b10000000 >> x);
            } else {
                println!("Warning: Out of bounds VRAM write: {}", idx);
            }
        }
    }

    (ch8.draw_callback)(ch8.display);
}

pub fn add_vx_to_i(ch8: &mut Chip8, x: uint) {
    ch8.i += x as u16;
}

pub fn copy_v0_through_vx_to_mem(ch8: &mut Chip8, x: uint) {
    if x == 0 {
        return;
    }
    copy_memory(ch8.ram.mut_slice(ch8.i as uint, ch8.i as uint + x),
                ch8.v.slice(0, x));
}

pub fn read_v0_through_vx_from_mem(ch8: &mut Chip8, x: uint) {
    if x == 0 {
        return;
    }
    copy_memory(ch8.v.mut_slice(0, x),
                ch8.ram.slice(ch8.i as uint, ch8.i as uint + x));
}

pub fn skip_next_vx_ne_vy(ch8: &mut Chip8, x: uint, y: uint) {
    if ch8.v[x] != ch8.v[y] {
        ch8.pc += 2;
    }
}

// Fx33 - LD B, Vx
// Store BCD representation of Vx in memory locations I, I+1, and I+2.
//
// The interpreter takes the decimal value of Vx, and places the hundreds
// digit in memory at location in I, the tens digit at location I+1,
// and the ones digit at location I+2.
pub fn store_bcd_of_vx_to_i(ch8: &mut Chip8, x: uint) {
    let num = ch8.v[x];
    let h = num / 100;
    let t = (num - h * 100) / 10;
    let o = (num - h * 100 - t * 10);
    ch8.ram[ch8.i as uint] = h;
    ch8.ram[ch8.i as uint + 1] = t;
    ch8.ram[ch8.i as uint + 2] = o;
}

// Fx29 - LD F, Vx
// Set I = location of sprite for digit Vx.
//
// The value of I is set to the location for the hexadecimal sprite
// corresponding to the value of Vx. See section 2.4, Display, for more
// information on the Chip-8 hexadecimal font.
//
// For crusty-chip, the fontset is stored at 0x000
pub fn set_i_to_loc_of_digit_vx(ch8: &mut Chip8, x: uint) {
    ch8.i = (ch8.v[x] * 5) as u16;
}

// Fx0A - LD Vx, K
// Wait for a key press, store the value of the key in Vx.
//
// All execution stops until a key is pressed, then the value of that key
// is stored in Vx.
pub fn wait_for_keypress_store_in_vx(ch8: &mut Chip8, x: uint) {
    ch8.keypress_wait.wait = true;
    ch8.keypress_wait.vx = x;
}

// Fx15 - LD DT, Vx
// Set delay timer = Vx.
//
// DT is set equal to the value of Vx.
pub fn set_delay_timer(ch8: &mut Chip8, x: u8) {
    ch8.delay_timer = x;
}

// Fx18 - LD ST, Vx
// Set sound timer = Vx.
//
// ST is set equal to the value of Vx.
pub fn set_sound_timer(ch8: &mut Chip8, x: u8) {
    ch8.sound_timer = x;
}

// Fx07 - LD Vx, DT
// Set Vx = delay timer value.
//
// The value of DT is placed into Vx.
pub fn set_vx_to_delay_timer(ch8: &mut Chip8, x: uint) {
    ch8.v[x] = ch8.delay_timer;
}

// ExA1 - SKNP Vx
// Skip next instruction if key with the value of Vx is not pressed.
//
// Checks the keyboard, and if the key corresponding to the value of
// Vx is currently in the up position, PC is increased by 2.
pub fn skip_next_key_vx_not_pressed(ch8: &mut Chip8, x: uint) {
    if !ch8.keys[ch8.v[x] as uint] {
        ch8.pc += 2;
    }
}

#[test]
fn test_strore_bcd_of_vx_to_i() {
    let mut ch8 = Chip8::new(|_| {});
    ch8.v[0] = 146;
    ch8.i = 0;
    store_bcd_of_vx_to_i(&mut ch8, 0);
    assert!(ch8.ram[0] == 1);
    assert!(ch8.ram[1] == 4);
    assert!(ch8.ram[2] == 6);
}
<commit_msg>Properly(?) implement set_vx_to_vx_shl_1<commit_after>use super::Chip8;
use std::slice::bytes::copy_memory;

// 0nnn - SYS addr
// Jump to a machine code routine at nnn.
//
// This instruction is only used on the old computers on which Chip-8 was
// originally implemented. It is ignored by modern interpreters.
pub fn jump_to_sys_routine(ch8: &mut Chip8, addr: uint) {
    // Do nothing
}

// 00E0 - CLS
// Clear the display.
pub fn clear_display(ch8: &mut Chip8) {
    for px in ch8.display.mut_iter() {
        *px = 0;
    }
}

// 00EE - RET
// Return from a subroutine.
//
// The interpreter sets the program counter to the address at the top of
// the stack, then subtracts 1 from the stack pointer.
pub fn ret_from_subroutine(ch8: &mut Chip8) {
    ch8.pc = ch8.stack[ch8.sp as uint];
    ch8.sp -= 1;
}

// 1nnn - JP addr
// Jump to location nnn.
//
// The interpreter sets the program counter to nnn.
pub fn jump_addr(ch8: &mut Chip8, addr: u16) {
    ch8.pc = addr;
}

// 2nnn - CALL addr
// Call subroutine at nnn.
//
// The interpreter increments the stack pointer, then puts the current PC
// on the top of the stack. The PC is then set to nnn.
pub fn call_subroutine(ch8: &mut Chip8, addr: uint) {
    ch8.sp += 1;
    ch8.stack[ch8.sp as uint] = ch8.pc;
    ch8.pc = addr as u16;
}

// 3xkk - SE Vx, byte
// Skip next instruction if Vx = kk.
//
// The interpreter compares register Vx to kk, and if they are equal,
// increments the program counter by 2.
pub fn skip_next_vx_eq(ch8: &mut Chip8, x: uint, to: u8) {
    if ch8.v[x] == to {
        ch8.pc += 2;
    }
}

// 4xkk - SNE Vx, byte
// Skip next instruction if Vx != kk.
//
// The interpreter compares register Vx to kk, and if they are not equal,
// increments the program counter by 2.
pub fn skip_next_vx_ne(ch8: &mut Chip8, x: uint, to: u8) {
    if ch8.v[x] != to {
        ch8.pc += 2;
    }
}

// 5xy0 - SE Vx, Vy
// Skip next instruction if Vx = Vy.
//
// The interpreter compares register Vx to register Vy, and if they are
// equal, increments the program counter by 2.
pub fn skip_next_vx_eq_vy(ch8: &mut Chip8, x: uint, y: uint) {
    if ch8.v[x] == ch8.v[y] {
        ch8.pc += 2;
    }
}

// 6xkk - LD Vx, byte
// Set Vx = kk.
//
// The interpreter puts the value kk into register Vx.
pub fn set_vx_byte(ch8: &mut Chip8, x: uint, byte: u8) {
    ch8.v[x] = byte;
}

// 7xkk - ADD Vx, byte
// Set Vx = Vx + kk.
//
// Adds the value kk to the value of register Vx, then stores the
// result in Vx.
pub fn add_vx_byte(ch8: &mut Chip8, x: uint, byte: u8) {
    ch8.v[x] += byte;
}

// 8xy0 - LD Vx, Vy
// Set Vx = Vy.
//
// Stores the value of register Vy in register Vx.
pub fn set_vx_to_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] = ch8.v[y];
}

// 8xy2 - AND Vx, Vy
// Set Vx = Vx AND Vy.
//
// Performs a bitwise AND on the values of Vx and Vy, then stores the
// result in Vx. A bitwise AND compares the corrseponding bits from two
// values, and if both bits are 1, then the same bit in the result is also
// 1. Otherwise, it is 0.
pub fn set_vx_to_vx_and_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] &= ch8.v[y];
}

// 8xy3 - XOR Vx, Vy
// Set Vx = Vx XOR Vy.
//
// Performs a bitwise exclusive OR on the values of Vx and Vy, then stores
// the result in Vx. An exclusive OR compares the corrseponding bits from
// two values, and if the bits are not both the same, then the
// corresponding bit in the result is set to 1. Otherwise, it is 0.
pub fn set_vx_to_vx_xor_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[x] ^= ch8.v[y];
}

// 8xy4 - ADD Vx, Vy
// Set Vx = Vx + Vy, set VF = carry.
//
// The values of Vx and Vy are added together. If the result is greater than
// 8 bits (i.e., > 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits
// of the result are kept, and stored in Vx.
pub fn add_vx_vy(ch8: &mut Chip8, x: uint, y: uint) {
    let result = (ch8.v[x] + ch8.v[y]) as u16;
    ch8.v[0xF] = (result > 255) as u8;
    ch8.v[x] = result as u8;
}

// 8xy5 - SUB Vx, Vy
// Set Vx = Vx - Vy, set VF = NOT borrow.
//
// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx,
// and the results stored in Vx.
pub fn sub_vx_vy(ch8: &mut Chip8, x: uint, y: uint) {
    ch8.v[0xF] = (ch8.v[x] > ch8.v[y]) as u8;
    ch8.v[x] -= ch8.v[y];
}

// 8xyE - SHL Vx {, Vy}
// Set Vx = Vx SHL 1.
//
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise
// to 0. Then Vx is multiplied by 2.
pub fn set_vx_to_vx_shl_1(ch8: &mut Chip8, x: uint) {
    ch8.v[0xF] = if check_bit(ch8.v[x], 7) {1} else {0};
    ch8.v[x] *= 2;
}

fn check_bit(byte: u8, pos: uint) -> bool {
    byte & (1 << pos) != 0
}

#[test]
fn test_check_bit() {
    assert!(check_bit(0b10000000, 7));
    for i in range(0u, 7) {
        assert!(!check_bit(0b10000000, i));
    }
    assert!(check_bit(0b01000000, 6));
    assert!(check_bit(0b00100000, 5));
    assert!(check_bit(0b00010000, 4));
    assert!(check_bit(0b00001000, 3));
    assert!(check_bit(0b00000100, 2));
    assert!(check_bit(0b00000010, 1));
    assert!(check_bit(0b00000001, 0));
}

pub fn set_i(ch8: &mut Chip8, to: u16) {
    ch8.i = to;
}

pub fn set_vx_rand_and(ch8: &mut Chip8, x: uint, to: u8) {
    use std::rand::{task_rng, Rng};
    let mut rgen = task_rng();
    ch8.v[x] = rgen.gen::<u8>() & to;
}

pub fn display_sprite(ch8: &mut Chip8, vx: uint, vy: uint, n: uint) {
    use super::{ DISPLAY_WIDTH, DISPLAY_HEIGHT };
    let x_off = ch8.v[vx] as uint;
    let y_off = ch8.v[vy] as uint * DISPLAY_WIDTH;
    let offset = x_off + y_off;

    for mut y in range(0u, n) {
        if y >= DISPLAY_HEIGHT {
            y = y - DISPLAY_HEIGHT;
        }
        let b = ch8.ram[ch8.i as uint + y];
        for mut x in range(0u, 8) {
            if x >= DISPLAY_WIDTH {
                x = x - DISPLAY_WIDTH;
            }
            let idx = offset + (y * DISPLAY_WIDTH) + x;
            if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                ch8.display[idx] ^= b & (0b10000000 >> x);
            } else {
                println!("Warning: Out of bounds VRAM write: {}", idx);
            }
        }
    }

    (ch8.draw_callback)(ch8.display);
}

pub fn add_vx_to_i(ch8: &mut Chip8, x: uint) {
    ch8.i += x as u16;
}

pub fn copy_v0_through_vx_to_mem(ch8: &mut Chip8, x: uint) {
    if x == 0 {
        return;
    }
    copy_memory(ch8.ram.mut_slice(ch8.i as uint, ch8.i as uint + x),
                ch8.v.slice(0, x));
}

pub fn read_v0_through_vx_from_mem(ch8: &mut Chip8, x: uint) {
    if x == 0 {
        return;
    }
    copy_memory(ch8.v.mut_slice(0, x),
                ch8.ram.slice(ch8.i as uint, ch8.i as uint + x));
}

pub fn skip_next_vx_ne_vy(ch8: &mut Chip8, x: uint, y: uint) {
    if ch8.v[x] != ch8.v[y] {
        ch8.pc += 2;
    }
}

// Fx33 - LD B, Vx
// Store BCD representation of Vx in memory locations I, I+1, and I+2.
//
// The interpreter takes the decimal value of Vx, and places the hundreds
// digit in memory at location in I, the tens digit at location I+1,
// and the ones digit at location I+2.
pub fn store_bcd_of_vx_to_i(ch8: &mut Chip8, x: uint) {
    let num = ch8.v[x];
    let h = num / 100;
    let t = (num - h * 100) / 10;
    let o = (num - h * 100 - t * 10);
    ch8.ram[ch8.i as uint] = h;
    ch8.ram[ch8.i as uint + 1] = t;
    ch8.ram[ch8.i as uint + 2] = o;
}

// Fx29 - LD F, Vx
// Set I = location of sprite for digit Vx.
//
// The value of I is set to the location for the hexadecimal sprite
// corresponding to the value of Vx. See section 2.4, Display, for more
// information on the Chip-8 hexadecimal font.
//
// For crusty-chip, the fontset is stored at 0x000
pub fn set_i_to_loc_of_digit_vx(ch8: &mut Chip8, x: uint) {
    ch8.i = (ch8.v[x] * 5) as u16;
}

// Fx0A - LD Vx, K
// Wait for a key press, store the value of the key in Vx.
//
// All execution stops until a key is pressed, then the value of that key
// is stored in Vx.
pub fn wait_for_keypress_store_in_vx(ch8: &mut Chip8, x: uint) {
    ch8.keypress_wait.wait = true;
    ch8.keypress_wait.vx = x;
}

// Fx15 - LD DT, Vx
// Set delay timer = Vx.
//
// DT is set equal to the value of Vx.
pub fn set_delay_timer(ch8: &mut Chip8, x: u8) {
    ch8.delay_timer = x;
}

// Fx18 - LD ST, Vx
// Set sound timer = Vx.
//
// ST is set equal to the value of Vx.
pub fn set_sound_timer(ch8: &mut Chip8, x: u8) {
    ch8.sound_timer = x;
}

// Fx07 - LD Vx, DT
// Set Vx = delay timer value.
//
// The value of DT is placed into Vx.
pub fn set_vx_to_delay_timer(ch8: &mut Chip8, x: uint) {
    ch8.v[x] = ch8.delay_timer;
}

// ExA1 - SKNP Vx
// Skip next instruction if key with the value of Vx is not pressed.
//
// Checks the keyboard, and if the key corresponding to the value of
// Vx is currently in the up position, PC is increased by 2.
pub fn skip_next_key_vx_not_pressed(ch8: &mut Chip8, x: uint) {
    if !ch8.keys[ch8.v[x] as uint] {
        ch8.pc += 2;
    }
}

#[test]
fn test_strore_bcd_of_vx_to_i() {
    let mut ch8 = Chip8::new(|_| {});
    ch8.v[0] = 146;
    ch8.i = 0;
    store_bcd_of_vx_to_i(&mut ch8, 0);
    assert!(ch8.ram[0] == 1);
    assert!(ch8.ram[1] == 4);
    assert!(ch8.ram[2] == 6);
}
<|endoftext|>


<commit_before>// DOCS

#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", deny(warnings))]

extern crate iron;
extern crate oven;
extern crate cookie;
extern crate persistent;

use iron::prelude::*;
use iron::typemap::Key;
use iron::middleware;
use oven::prelude::*;

/// Re-export of the Cookie class.
pub use cookie::Cookie;

/// Iron middleware providing user loging management
///
/// Stores the configuration in persistent data and adds an oven with the specified key.
pub struct LoginManager {
    signing_key: Vec<u8>,
    /// Configuration for this manager
    pub config: Config,
}

impl LoginManager {
    /// Construct a new login middleware using the provided signing key
    pub fn new(signing_key: Vec<u8>) -> LoginManager {
        LoginManager {
            signing_key: signing_key,
            config: Config::defaults(),
        }
    }
}

impl middleware::AroundMiddleware for LoginManager {
    fn around(self, handler: Box<middleware::Handler>) -> Box<middleware::Handler> {
        let mut ch = Chain::new(handler);
        let key = self.signing_key;

        ch.link(oven::new(key));
        ch.link(persistent::Read::<Config>::both(self.config));

        Box::new(ch)
    }
}

/// Configuration
#[derive(Debug, Clone)]
pub struct Config {
    /// This cookie contains the default values that will be used for session cookies.
    ///
    /// You may e.g. override `httponly` or `secure` however you wish.
    pub cookie_base: Cookie,
}

impl Config {
    /// Construct a configuration instance with default values
    pub fn defaults() -> Self {
        Config {
            cookie_base: {
                let mut c = Cookie::new("logged_in_user".to_owned(), "".to_owned());
                c.httponly = true;
                c.path = Some("/".to_owned());
                c
            },
        }
    }
}

impl Key for Config { type Value = Config; }

/// Trait repesenting an authenticated user
pub trait User: Send + Sync + Sized {
    /// Create a `User` instance from a user id
    fn from_user_id(request: &mut Request, user_id: &str) -> Option<Self>;
    /// Get the user_id associated with this `User`
    fn get_user_id(&self) -> String;
    /// Create a `Login<Self>` instance (no need to override)
    fn get_login(request: &mut Request) -> Login<Self> {
        Login::from_request(request)
    }
}

/// Login state
///
/// To construct this within a request, use `User::get_login()`
pub struct Login<U: User> {
    user: Option<U>,
    config: Config,
}

impl<U: User> Login<U> {
    fn from_request(request: &mut Request) -> Login<U> {
        let config = (*request.get::<persistent::Read<Config>>().unwrap()).clone();
        let user_id = match request.get_cookie(&config.cookie_base.name) {
            Some(c) if !c.value.is_empty() => Some(c.value.clone()),
            _ => None,
        };

        Login {
            user: user_id.and_then(|user_id| U::from_user_id(request, &user_id)),
            config: config,
        }
    }

    /// Unwrap into the `User` instance
    pub fn get_user(self) -> Option<U> {
        self.user
    }

    /// Log in as the passed `User` instance
    pub fn log_in(mut self, user: U) -> LoginModifier<U> {
        self.user = Some(user);
        LoginModifier { login: self }
    }

    /// Log out (clearing the cookie)
    pub fn log_out(mut self) -> LoginModifier<U> {
        self.user = None;
        LoginModifier { login: self }
    }
}

/// Iron modifier that updates the cookie
pub struct LoginModifier<U: User> {
    login: Login<U>,
}
impl<U: User> iron::modifier::Modifier<Response> for LoginModifier<U> {
    fn modify(self, response: &mut Response) {
        response.set_cookie({
            let mut x = self.login.config.cookie_base.clone();
            x.value = self.login.user
                .map_or_else(|| "".to_owned(), |u| u.get_user_id());
            x
        });
    }
}
<commit_msg>Clippy leftovers<commit_after>// DOCS

extern crate iron;
extern crate oven;
extern crate cookie;
extern crate persistent;

use iron::prelude::*;
use iron::typemap::Key;
use iron::middleware;
use oven::prelude::*;

/// Re-export of the Cookie class.
pub use cookie::Cookie;

/// Iron middleware providing user loging management
///
/// Stores the configuration in persistent data and adds an oven with the specified key.
pub struct LoginManager {
    signing_key: Vec<u8>,
    /// Configuration for this manager
    pub config: Config,
}

impl LoginManager {
    /// Construct a new login middleware using the provided signing key
    pub fn new(signing_key: Vec<u8>) -> LoginManager {
        LoginManager {
            signing_key: signing_key,
            config: Config::defaults(),
        }
    }
}

impl middleware::AroundMiddleware for LoginManager {
    fn around(self, handler: Box<middleware::Handler>) -> Box<middleware::Handler> {
        let mut ch = Chain::new(handler);
        let key = self.signing_key;

        ch.link(oven::new(key));
        ch.link(persistent::Read::<Config>::both(self.config));

        Box::new(ch)
    }
}

/// Configuration
#[derive(Debug, Clone)]
pub struct Config {
    /// This cookie contains the default values that will be used for session cookies.
    ///
    /// You may e.g. override `httponly` or `secure` however you wish.
    pub cookie_base: Cookie,
}

impl Config {
    /// Construct a configuration instance with default values
    pub fn defaults() -> Self {
        Config {
            cookie_base: {
                let mut c = Cookie::new("logged_in_user".to_owned(), "".to_owned());
                c.httponly = true;
                c.path = Some("/".to_owned());
                c
            },
        }
    }
}

impl Key for Config { type Value = Config; }

/// Trait repesenting an authenticated user
pub trait User: Send + Sync + Sized {
    /// Create a `User` instance from a user id
    fn from_user_id(request: &mut Request, user_id: &str) -> Option<Self>;
    /// Get the user_id associated with this `User`
    fn get_user_id(&self) -> String;
    /// Create a `Login<Self>` instance (no need to override)
    fn get_login(request: &mut Request) -> Login<Self> {
        Login::from_request(request)
    }
}

/// Login state
///
/// To construct this within a request, use `User::get_login()`
pub struct Login<U: User> {
    user: Option<U>,
    config: Config,
}

impl<U: User> Login<U> {
    fn from_request(request: &mut Request) -> Login<U> {
        let config = (*request.get::<persistent::Read<Config>>().unwrap()).clone();
        let user_id = match request.get_cookie(&config.cookie_base.name) {
            Some(c) if !c.value.is_empty() => Some(c.value.clone()),
            _ => None,
        };

        Login {
            user: user_id.and_then(|user_id| U::from_user_id(request, &user_id)),
            config: config,
        }
    }

    /// Unwrap into the `User` instance
    pub fn get_user(self) -> Option<U> {
        self.user
    }

    /// Log in as the passed `User` instance
    pub fn log_in(mut self, user: U) -> LoginModifier<U> {
        self.user = Some(user);
        LoginModifier { login: self }
    }

    /// Log out (clearing the cookie)
    pub fn log_out(mut self) -> LoginModifier<U> {
        self.user = None;
        LoginModifier { login: self }
    }
}

/// Iron modifier that updates the cookie
pub struct LoginModifier<U: User> {
    login: Login<U>,
}
impl<U: User> iron::modifier::Modifier<Response> for LoginModifier<U> {
    fn modify(self, response: &mut Response) {
        response.set_cookie({
            let mut x = self.login.config.cookie_base.clone();
            x.value = self.login.user
                .map_or_else(|| "".to_owned(), |u| u.get_user_id());
            x
        });
    }
}
<|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.

// The crazy macro_rules magic in this file is thanks to dtolnay@
// and is a way of attaching rustdoc to each of the possible directives
// within the include_cpp outer macro. None of the directives actually
// do anything - all the magic is handled entirely by
// autocxx_macro::include_cpp_impl.

/// Include some C++ headers in your Rust project.
///
/// This macro allows you to include one or more C++ headers within
/// your Rust code, and call their functions fairly naturally.
///
/// # Examples
///
/// C++ header (`input.h`):
/// ```cpp
/// #include <cstdint>
///
/// uint32_t do_math(uint32_t a);
/// ```
///
/// Rust code:
/// ```
/// # use autocxx_macro::include_cpp_impl as include_cpp;
/// include_cpp!(
/// #   parse_only
///     #include "input.h"
///     allow("do_math")
/// );
///
/// # mod ffi { pub mod cxxbridge { pub fn do_math(a: u32) -> u32 { a+3 } } }
/// # fn main() {
/// ffi::cxxbridge::do_math(3);
/// # }
/// ```
///
/// # Configuring the build
///
/// To build this, you'll need to:
/// * Educate the procedural macro about where to find the C++ headers. Set the
///   `AUTOCXX_INC` environment variable to a list of directories to search.
/// * Build the C++ side of the bindings. You'll need to use the `autocxx-gen`
///   crate (or similar) to process the same .rs code into C++ header and
///   implementation files.
///
/// # Syntax
///
/// Within the brackets of the `include_cxx!(...)` macro, you should provide
/// a list of at least the following:
///
/// * `#include "cpp_header.h"`: a header filename to parse and include
/// * `allow("type_or_function_name")`: a type or function name whose declaration
///   should be made available to C++.
///
/// Other directives are possible as documented in this crate.
///
/// # How to allow structs
///
/// All C++ types can be owned within a [UniquePtr][autocxx_engine::cxx::UniquePtr]
/// within Rust. To let this be possible, simply pass the names of these
/// types within [allow] (or just [allow] any function which requires these types).
///
/// However, only _some_ C++ `struct`s can be owned _by value_ within Rust. Those
/// types must be freely byte-copyable, because Rust is free to do that at
/// any time. If you believe your `struct` meets those criteria, you can
/// use [allow_pod] instead.
///
/// Use [allow] under normal circumstances, but [allow_pod] only for structs
/// where you absolutely do need to pass them truly by value and have direct field access.
///
/// This doesn't just make a difference to the generated code for the type;
/// it also makes a difference to any functions which take or return that type.
/// If there's a C++ function which takes a struct by value, but that struct
/// is not declared as POD-safe, then we'll generate wrapper functions to move
/// that type into and out of [UniquePtr][autocxx_engine::cxx::UniquePtr]s.
///
///
/// # Generated code
///
/// You will find that this macro expands to the equivalent of:
///
/// ```
/// mod ffi {
///     pub fn do_math(a: u32) -> u32
/// #   { a+3 }
///     pub const kMyCxxConst: i32 = 3;
///     pub const MY_PREPROCESSOR_DEFINITION: i64 = 3i64;
/// }
/// ```
///
/// # Namespaces
///
/// At present, C++ namespaces are partially handled. autocxx will understand
/// and generate Rust code from C++ code which has namespaces, but a flat structure
/// will be generated on the Rust side. That means that you can't have two
/// types or two functions with the same name within different namespaces. This
/// is a temporary restriction.
#[macro_export]
macro_rules! include_cpp {
    (
        $(#$include:ident $lit:literal)*
        $($mac:ident!($($arg:tt)*))*
    ) => {
        $($crate::$include!{__docs})*
        $($crate::$mac!{__docs})*
        $crate::include_cpp_impl! {
            $(#include $lit)*
            $($mac!($($arg)*))*
        }
    };
}

/// Include a C++ header. A directive to be included inside
/// [include_cpp] - see [include_cpp] for details
#[macro_export]
macro_rules! include {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate Rust bindings for the given C++ type or function.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
/// See also [allow_pod].
#[macro_export]
macro_rules! allow {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate as "plain old data".
/// Generate Rust bindings for the given C++ type such that
/// it can be passed and owned by value in Rust. This only works
/// for C++ types which have trivial move constructors and no
/// destructor - you'll encounter a compile error otherwise.
/// If your type doesn't match that description, use [allow]
/// instead, and own the type using [UniquePtr][autocxx_engine::cxx::UniquePtr].
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! allow_pod {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Skip the normal generation of a `make_string` function
/// and other utilities which we might generate normally.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! exclude_utilities {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

#[doc(hidden)]
#[macro_export]
macro_rules! usage {
    (__docs) => {};
    ($($tt:tt)*) => {
        compile_error! {r#"usage:  include_cpp! {
                   #include "path/to/header.h"
                   allow!(...)
                   allow_pod!(...)
               }
"#}
    };
}

#[doc(hidden)]
pub use autocxx_macro::include_cpp_impl;
<commit_msg>Documentation improvements.<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.

// The crazy macro_rules magic in this file is thanks to dtolnay@
// and is a way of attaching rustdoc to each of the possible directives
// within the include_cpp outer macro. None of the directives actually
// do anything - all the magic is handled entirely by
// autocxx_macro::include_cpp_impl.

/// Include some C++ headers in your Rust project.
///
/// This macro allows you to include one or more C++ headers within
/// your Rust code, and call their functions fairly naturally.
///
/// # Examples
///
/// C++ header (`input.h`):
/// ```cpp
/// #include <cstdint>
///
/// uint32_t do_math(uint32_t a);
/// ```
///
/// Rust code:
/// ```
/// # use autocxx_macro::include_cpp_impl as include_cpp;
/// include_cpp!(
/// #   parse_only
///     #include "input.h"
///     allow("do_math")
/// );
///
/// # mod ffi { pub fn do_math(a: u32) -> u32 { a+3 } }
/// # fn main() {
/// ffi::do_math(3);
/// # }
/// ```
///
/// # Configuring the build
///
/// To build this, you'll need to:
/// * Educate the procedural macro about where to find the C++ headers. Set the
///   `AUTOCXX_INC` environment variable to a list of directories to search.
/// * Build the C++ side of the bindings. You'll need to use the `autocxx-gen`
///   crate (or similar) to process the same .rs code into C++ header and
///   implementation files.
///
/// # Syntax
///
/// Within the brackets of the `include_cxx!(...)` macro, you should provide
/// a list of at least the following:
///
/// * `#include "cpp_header.h"`: a header filename to parse and include
/// * `allow("type_or_function_name")`: a type or function name whose declaration
///   should be made available to C++.
///
/// Other directives are possible as documented in this crate.
///
/// # How to allow structs
///
/// All C++ types can be owned within a [UniquePtr][autocxx_engine::cxx::UniquePtr]
/// within Rust. To let this be possible, simply pass the names of these
/// types within [allow] (or just [allow] any function which requires these types).
///
/// However, only _some_ C++ `struct`s can be owned _by value_ within Rust. Those
/// types must be freely byte-copyable, because Rust is free to do that at
/// any time. If you believe your `struct` meets those criteria, you can
/// use [allow_pod] instead.
///
/// Use [allow] under normal circumstances, but [allow_pod] only for structs
/// where you absolutely do need to pass them truly by value and have direct field access.
///
/// This doesn't just make a difference to the generated code for the type;
/// it also makes a difference to any functions which take or return that type.
/// If there's a C++ function which takes a struct by value, but that struct
/// is not declared as POD-safe, then we'll generate wrapper functions to move
/// that type into and out of [UniquePtr][autocxx_engine::cxx::UniquePtr]s.
///
///
/// # Generated code
///
/// You will find that this macro expands to the equivalent of:
///
/// ```no_run
/// mod ffi {
///     pub fn do_math(a: u32) -> u32
/// #   { a+3 }
///     pub const kMyCxxConst: i32 = 3;
///     pub const MY_PREPROCESSOR_DEFINITION: i64 = 3i64;
/// }
/// ```
///
/// # Built-in types
///
/// The generated code uses `cxx` for interop: see that crate for many important
/// considerations including safety and the list of built-in types, for example
/// [UniquePtr][autocxx_engine::cxx::UniquePtr] and
/// [CxxString][autocxx_engine::cxx::CxxString].
///
/// # Making strings
///
/// Unless you use [exclude_utilities], you will find a function
/// called `make_string` exists inside the generated `ffi` block:
///
/// ```no_run
/// mod ffi {
/// # use autocxx_engine::cxx::UniquePtr;
/// # use autocxx_engine::cxx::CxxString;
///     pub fn make_string(str_: &str) -> UniquePtr<CxxString>
/// #   { unreachable!() }
/// }
/// ```
///
/// # Making other C++ types
///
/// Types gain a `_make_unique` function. At present this is not
/// an associated function; it's simply the type name followed by
/// that suffix.
///
/// ```
/// mod ffi {
/// # struct UniquePtr<T>(T);
///     struct Bob {
///         a: u32,
///     }
///     pub fn Bob_make_unique() -> UniquePtr<Bob>
/// #   { unreachable!() }
/// }
/// ```
/// # Preprocessor symbols
///
/// `#define` and other preprocessor symbols will appear as constants.
/// For integers this is straightforward; for strings they appear
/// as `[u8]` with a null terminator. To get a string, do this:
///
/// ```cpp
/// #define BOB "Hello"
/// ```
///
/// ```
/// # mod ffi { pub static BOB: [u8; 6] = [72u8, 101u8, 108u8, 108u8, 111u8, 0u8]; }
/// assert_eq!(std::str::from_utf8(&ffi::BOB).unwrap().trim_end_matches(char::from(0)), "Hello");
/// ```
///
/// # Namespaces
///
/// At present, C++ namespaces are partially handled. autocxx will understand
/// and generate Rust code from C++ code which has namespaces, but a flat structure
/// will be generated on the Rust side. That means that you can't have two
/// types or two functions with the same name within different namespaces. This
/// is a temporary restriction.
#[macro_export]
macro_rules! include_cpp {
    (
        $(#$include:ident $lit:literal)*
        $($mac:ident!($($arg:tt)*))*
    ) => {
        $($crate::$include!{__docs})*
        $($crate::$mac!{__docs})*
        $crate::include_cpp_impl! {
            $(#include $lit)*
            $($mac!($($arg)*))*
        }
    };
}

/// Include a C++ header. A directive to be included inside
/// [include_cpp] - see [include_cpp] for details
#[macro_export]
macro_rules! include {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate Rust bindings for the given C++ type or function.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
/// See also [allow_pod].
#[macro_export]
macro_rules! allow {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate as "plain old data".
/// Generate Rust bindings for the given C++ type such that
/// it can be passed and owned by value in Rust. This only works
/// for C++ types which have trivial move constructors and no
/// destructor - you'll encounter a compile error otherwise.
/// If your type doesn't match that description, use [allow]
/// instead, and own the type using [UniquePtr][autocxx_engine::cxx::UniquePtr].
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! allow_pod {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Skip the normal generation of a `make_string` function
/// and other utilities which we might generate normally.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! exclude_utilities {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

#[doc(hidden)]
#[macro_export]
macro_rules! usage {
    (__docs) => {};
    ($($tt:tt)*) => {
        compile_error! {r#"usage:  include_cpp! {
                   #include "path/to/header.h"
                   allow!(...)
                   allow_pod!(...)
               }
"#}
    };
}

#[doc(hidden)]
pub use autocxx_macro::include_cpp_impl;
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_uint, c_double};

/// Typedef for an "apply" function - used to manipulate system or application settings.
pub type poet_apply_func = extern fn(states: *mut c_void,
                                     num_states: c_uint,
                                     id: c_uint,
                                     last_id: c_uint);

/// Typedef for "current state" function - used to try and determine the current system or
/// application state.
pub type poet_curr_state_func = extern fn(states: *const c_void,
                                          num_states: c_uint,
                                          curr_state_id: *mut c_uint) -> i32;

#[repr(C)]
/// Representation of native struct `poet_control_state_t`.
pub struct poet_control_state_t {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

#[repr(C)]
/// Representation of native struct `poet_cpu_state_t`.
pub struct poet_cpu_state_t {
    pub id: c_uint,
    pub freq: c_uint,
    pub cores: c_uint,
}

#[repr(C)]
pub struct poet_state;

extern {

    // Core functions - poet.h

    pub fn poet_init(perf_goal: c_double,
                     num_system_states: c_uint,
                     control_states: *mut poet_control_state_t,
                     apply_states: *mut poet_cpu_state_t,
                     apply_func: poet_apply_func,
                     curr_state_func: poet_curr_state_func,
                     period: c_uint,
                     buffer_depth: c_uint,
                     log_filename: *const c_char) -> *mut poet_state;

    pub fn poet_apply_control(state: *mut poet_state,
                              id: u64,
                              perf: c_double,
                              pwr: c_double);

    pub fn poet_destroy(state: *mut poet_state);

    // Configuration/utility functions - poet_config.h

    pub fn apply_cpu_config(states: *mut c_void,
                            num_states: c_uint,
                            id: c_uint,
                            last_id: c_uint);

    pub fn get_control_states(path: *const c_char,
                              states: *mut *mut poet_control_state_t,
                              num_states: *mut c_uint) -> c_int;

    pub fn get_cpu_states(path: *const c_char,
                          states: *mut *mut poet_cpu_state_t,
                          num_states: *mut c_uint) -> c_int;

    pub fn get_current_cpu_state(states: *const c_void,
                                 num_states: c_uint,
                                 curr_state_id: *mut c_uint) -> c_int;

}
<commit_msg>Per Rust docs, use enum to represent opaque C struct<commit_after>#![allow(non_camel_case_types)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_uint, c_double};

/// Typedef for an "apply" function - used to manipulate system or application settings.
pub type poet_apply_func = extern fn(states: *mut c_void,
                                     num_states: c_uint,
                                     id: c_uint,
                                     last_id: c_uint);

/// Typedef for "current state" function - used to try and determine the current system or
/// application state.
pub type poet_curr_state_func = extern fn(states: *const c_void,
                                          num_states: c_uint,
                                          curr_state_id: *mut c_uint) -> i32;

#[repr(C)]
/// Representation of native struct `poet_control_state_t`.
pub struct poet_control_state_t {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

#[repr(C)]
/// Representation of native struct `poet_cpu_state_t`.
pub struct poet_cpu_state_t {
    pub id: c_uint,
    pub freq: c_uint,
    pub cores: c_uint,
}

/// Representation of the opaque native struct `poet_state`.
pub enum poet_state {}

extern {

    // Core functions - poet.h

    pub fn poet_init(perf_goal: c_double,
                     num_system_states: c_uint,
                     control_states: *mut poet_control_state_t,
                     apply_states: *mut poet_cpu_state_t,
                     apply_func: poet_apply_func,
                     curr_state_func: poet_curr_state_func,
                     period: c_uint,
                     buffer_depth: c_uint,
                     log_filename: *const c_char) -> *mut poet_state;

    pub fn poet_apply_control(state: *mut poet_state,
                              id: u64,
                              perf: c_double,
                              pwr: c_double);

    pub fn poet_destroy(state: *mut poet_state);

    // Configuration/utility functions - poet_config.h

    pub fn apply_cpu_config(states: *mut c_void,
                            num_states: c_uint,
                            id: c_uint,
                            last_id: c_uint);

    pub fn get_control_states(path: *const c_char,
                              states: *mut *mut poet_control_state_t,
                              num_states: *mut c_uint) -> c_int;

    pub fn get_cpu_states(path: *const c_char,
                          states: *mut *mut poet_cpu_state_t,
                          num_states: *mut c_uint) -> c_int;

    pub fn get_current_cpu_state(states: *const c_void,
                                 num_states: c_uint,
                                 curr_state_id: *mut c_uint) -> c_int;

}
<|endoftext|>