<commit_before>pub mod window;
pub mod widgets;
pub mod renderer;

use std::cmp::{max, min};

use nalgebra;

use self::renderer::{Color, ColoredRectangle, Painting};
use self::widgets::Widget;

pub type Point = nalgebra::Vector2<i32>;
pub type Size = nalgebra::Vector2<i32>;

#[derive(Clone, Copy, Debug)]
pub struct Bbox {
    pub min: Point,
    pub max: Point,
}

impl Bbox {
    pub fn new(min: Point, max: Point) -> Self {
        Bbox { min, max }
    }

    pub fn with_size(origin: Point, size: Size) -> Self {
        Bbox::new(origin, origin + size)
    }

    pub fn size(&self) -> Size {
        self.max - self.min
    }

    pub fn contains_point(&self, point: Point) -> bool {
        self.min <= point && self.max >= point
    }

    pub fn fits(&self, other: &Bbox) -> bool {
        self.min <= other.min && self.max >= other.max
    }
}

pub struct View {
    bbox: Bbox,
    space_div: SpaceDiv,
}

impl View {
    pub fn new(bbox: Bbox) -> Self {
        Self {
            bbox,
            space_div: SpaceDiv::full()
                .vertical()
                .vert_align(DivAlignment::Min)
                .build(),
        }
    }

    pub fn add_div(&mut self, div: SpaceDiv) {
        self.space_div.add_div(div);
    }

    pub fn bbox(&self) -> &Bbox {
        &self.bbox
    }

    pub fn set_bbox(&mut self, bbox: Bbox) {
        self.bbox = bbox;
    }

    pub fn space_div(&self) -> &SpaceDiv {
        &self.space_div
    }

    pub fn draw(&self, painting: &mut Painting) {
        self.draw_div(&self.space_div, self.bbox, painting);
    }

    fn draw_div(&self, div: &SpaceDiv, div_bbox: Bbox, painting: &mut Painting) {
        painting.draw(ColoredRectangle(div_bbox, Color::rgba(1.0, 1.0, 0.0, 0.2)));

        if let Some(ref widget) = div.widget {
            widget.draw(div_bbox, painting);
        }

        for (div, bbox) in div.children(div_bbox) {
            self.draw_div(div, bbox, painting);
        }
    }
}

#[derive(Clone, Copy)]
pub struct DivUnitCalcData<'a> {
    pub div: &'a SpaceDiv,
    pub direction: DivDirection,
    pub parent_size: Size,
    pub remaining: i32,
}

pub enum DivUnit {
    /// Absolute pixels.
    Pixels(i32),
    /// Pixels relative to a parent.
    Relative(f32),
    /// Calculate the pixels dynamically through a closure.
    Calc(Box<Fn(DivUnitCalcData) -> i32>),
}

#[derive(Clone, Copy)]
pub enum DivDirection {
    Horizontal,
    Vertical,
}

#[derive(Clone, Copy)]
pub enum DivAlignment {
    Min,
    Max,
    Center,
}

pub struct SpaceDiv {
    width: DivUnit,
    height: DivUnit,
    min_width: Option<DivUnit>,
    min_height: Option<DivUnit>,
    max_width: Option<DivUnit>,
    max_height: Option<DivUnit>,
    layout_dir: DivDirection,
    hori_align: DivAlignment,
    vert_align: DivAlignment,
    widget: Option<Box<Widget>>,
    child_divs: Vec<SpaceDiv>,
}

impl SpaceDiv {
    pub fn full() -> SpaceDivBuilder {
        SpaceDivBuilder::new()
            .width(DivUnit::Relative(1.0))
            .height(DivUnit::Relative(1.0))
    }

    // Compute the layout of the children.
    pub fn children(&self, self_bbox: Bbox) -> SpaceDivIter<::std::slice::Iter<SpaceDiv>> {
        let total_size = self.child_divs.iter().fold(Size::new(0, 0), |total, div| {
            total + div.size_pixels(self_bbox.size(), DivDirection::Vertical, Point::new(0, 0))
        });
        SpaceDivIter::new(
            self.child_divs.iter(),
            total_size,
            self_bbox,
            self.layout_dir,
            self.hori_align,
            self.vert_align,
        )
    }

    pub fn add_div(&mut self, div: SpaceDiv) {
        self.child_divs.push(div);
    }

    /// Compute this div's size in pixels.
    fn size_pixels(&self, parent_size: Size, parent_dir: DivDirection, last_origin: Point) -> Size {
        let calc_data = DivUnitCalcData {
            div: &self,
            direction: self.layout_dir,
            parent_size: parent_size,
            remaining: match parent_dir {
                DivDirection::Horizontal => max(parent_size.x - last_origin.x, 0),
                DivDirection::Vertical => max(parent_size.y - last_origin.y, 0),
            },
        };

        let w = match self.width {
            DivUnit::Pixels(pix) => pix,
            DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
            DivUnit::Calc(ref f) => (*f)(calc_data),
        };
        let h = match self.height {
            DivUnit::Pixels(pix) => pix,
            DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
            DivUnit::Calc(ref f) => (*f)(calc_data),
        };

        // Apply min and max width to width
        let w = if let Some(ref mw) = self.max_width {
            let mw = match *mw {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            min(w, mw)
        } else {
            w
        };

        let w = if let Some(ref mw) = self.min_width {
            let mw = match *mw {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            max(w, mw)
        } else {
            w
        };

        // Apply min and max height to height
        let h = if let Some(ref mh) = self.max_height {
            let mh = match *mh {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            min(h, mh)
        } else {
            h
        };

        let h = if let Some(ref mh) = self.min_height {
            let mh = match *mh {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            max(h, mh)
        } else {
            h
        };

        Size::new(w, h)
    }
}

impl Default for SpaceDiv {
    fn default() -> Self {
        Self {
            width: DivUnit::Relative(1.0),
            height: DivUnit::Relative(1.0),
            min_width: None,
            min_height: None,
            max_width: None,
            max_height: None,
            layout_dir: DivDirection::Horizontal,
            hori_align: DivAlignment::Min,
            vert_align: DivAlignment::Min,
            widget: None,
            child_divs: Vec::new(),
        }
    }
}

/// Iterator that computes the positions and sizes of space divisions based on the
/// parent or containing bounding box.
/// This is essentially the layout engine.
pub struct SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    /// The space divisions to compute the layout of.
    space_divs: I,
    /// The sum total of all the space division sizes.
    total_size: Size,
    /// The containing (parent) bounding box.
    bbox: Bbox,
    /// The direction in with the layout grows.
    dir: DivDirection,
    /// The horizontal alignment.
    hori_align: DivAlignment,
    /// The vertical alignment.
    vert_align: DivAlignment,
    /// The current horizontal or vertical advance.
    cur: i32,
    /// The bottom-right coordinate of the last / previous division's bounding box.
    previous_end: Point,
}

impl<'a, I> SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    fn new(
        space_divs: I,
        total_size: Size,
        bbox: Bbox,
        dir: DivDirection,
        hori_align: DivAlignment,
        vert_align: DivAlignment,
    ) -> Self {
        Self {
            space_divs,
            total_size,
            bbox,
            dir,
            hori_align,
            vert_align,
            cur: 0,
            previous_end: Point::new(0, 0),
        }
    }
}

impl<'a, I> Iterator for SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    type Item = (&'a SpaceDiv, Bbox);

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(div) = self.space_divs.next() {
            let size = div.size_pixels(self.bbox.size(), self.dir, self.previous_end);

            // Compute offset coordinates from top-left.
            let offset_x = match self.hori_align {
                DivAlignment::Min => 0,
                DivAlignment::Max => self.bbox.size().x - size.x,
                DivAlignment::Center => match self.dir {
                    DivDirection::Horizontal => self.bbox.size().x / 2 - self.total_size.x / 2,
                    DivDirection::Vertical => self.bbox.size().x / 2 - size.x / 2,
                },
            };
            let offset_y = match self.vert_align {
                DivAlignment::Min => 0,
                DivAlignment::Max => self.bbox.size().y - size.y,
                DivAlignment::Center => match self.dir {
                    DivDirection::Horizontal => self.bbox.size().y / 2 - size.y / 2,
                    DivDirection::Vertical => self.bbox.size().y / 2 - self.total_size.y / 2,
                },
            };

            let origin = match self.dir {
                DivDirection::Horizontal => {
                    Point::new(self.cur + offset_x, self.bbox.min.y + offset_y)
                }
                DivDirection::Vertical => {
                    Point::new(self.bbox.min.x + offset_x, self.cur + offset_y)
                }
            };
            self.previous_end = origin + size;

            let div_bbox = Bbox::with_size(origin, size);

            // Compute directions and advance.
            let dir_x = match self.hori_align {
                DivAlignment::Max => -1,
                _ => 1,
            };
            let dir_y = match self.vert_align {
                DivAlignment::Max => -1,
                _ => 1,
            };

            self.cur += match self.dir {
                DivDirection::Horizontal => size.x * dir_x,
                DivDirection::Vertical => size.y * dir_y,
            };

            Some((div, div_bbox))
        } else {
            None
        }
    }
}

pub struct SpaceDivBuilder {
    current: SpaceDiv,
}

impl SpaceDivBuilder {
    pub fn new() -> Self {
        Self {
            current: Default::default(),
        }
    }

    pub fn width(mut self, width: DivUnit) -> Self {
        self.current.width = width;
        self
    }

    pub fn height(mut self, height: DivUnit) -> Self {
        self.current.height = height;
        self
    }

    pub fn min_width(mut self, min_width: DivUnit) -> Self {
        self.current.min_width = Some(min_width);
        self
    }

    pub fn min_height(mut self, min_height: DivUnit) -> Self {
        self.current.min_height = Some(min_height);
        self
    }

    pub fn max_width(mut self, max_width: DivUnit) -> Self {
        self.current.max_width = Some(max_width);
        self
    }

    pub fn max_height(mut self, max_height: DivUnit) -> Self {
        self.current.max_height = Some(max_height);
        self
    }

    pub fn horizontal(mut self) -> Self {
        self.current.layout_dir = DivDirection::Horizontal;
        self
    }

    pub fn vertical(mut self) -> Self {
        self.current.layout_dir = DivDirection::Vertical;
        self
    }

    pub fn hori_align(mut self, hori_align: DivAlignment) -> Self {
        self.current.hori_align = hori_align;
        self
    }

    pub fn vert_align(mut self, vert_align: DivAlignment) -> Self {
        self.current.vert_align = vert_align;
        self
    }

    pub fn widget(mut self, widget: Box<Widget>) -> Self {
        self.current.widget = Some(widget);
        self
    }

    pub fn add_div(mut self, div: SpaceDiv) -> Self {
        self.current.add_div(div);
        self
    }

    pub fn build(self) -> SpaceDiv {
        self.current
    }
}
<commit_msg>Don't draw the div bbox visualization anymore<commit_after>pub mod window;
pub mod widgets;
pub mod renderer;

use std::cmp::{max, min};

use nalgebra;

use self::renderer::{Color, ColoredRectangle, Painting};
use self::widgets::Widget;

pub type Point = nalgebra::Vector2<i32>;
pub type Size = nalgebra::Vector2<i32>;

#[derive(Clone, Copy, Debug)]
pub struct Bbox {
    pub min: Point,
    pub max: Point,
}

impl Bbox {
    pub fn new(min: Point, max: Point) -> Self {
        Bbox { min, max }
    }

    pub fn with_size(origin: Point, size: Size) -> Self {
        Bbox::new(origin, origin + size)
    }

    pub fn size(&self) -> Size {
        self.max - self.min
    }

    pub fn contains_point(&self, point: Point) -> bool {
        self.min <= point && self.max >= point
    }

    pub fn fits(&self, other: &Bbox) -> bool {
        self.min <= other.min && self.max >= other.max
    }
}

pub struct View {
    bbox: Bbox,
    space_div: SpaceDiv,
}

impl View {
    pub fn new(bbox: Bbox) -> Self {
        Self {
            bbox,
            space_div: SpaceDiv::full()
                .vertical()
                .vert_align(DivAlignment::Min)
                .build(),
        }
    }

    pub fn add_div(&mut self, div: SpaceDiv) {
        self.space_div.add_div(div);
    }

    pub fn bbox(&self) -> &Bbox {
        &self.bbox
    }

    pub fn set_bbox(&mut self, bbox: Bbox) {
        self.bbox = bbox;
    }

    pub fn space_div(&self) -> &SpaceDiv {
        &self.space_div
    }

    pub fn draw(&self, painting: &mut Painting) {
        self.draw_div(&self.space_div, self.bbox, painting);
    }

    fn draw_div(&self, div: &SpaceDiv, div_bbox: Bbox, painting: &mut Painting) {
        if let Some(ref widget) = div.widget {
            widget.draw(div_bbox, painting);
        }

        for (div, bbox) in div.children(div_bbox) {
            self.draw_div(div, bbox, painting);
        }
    }
}

#[derive(Clone, Copy)]
pub struct DivUnitCalcData<'a> {
    pub div: &'a SpaceDiv,
    pub direction: DivDirection,
    pub parent_size: Size,
    pub remaining: i32,
}

pub enum DivUnit {
    /// Absolute pixels.
    Pixels(i32),
    /// Pixels relative to a parent.
    Relative(f32),
    /// Calculate the pixels dynamically through a closure.
    Calc(Box<Fn(DivUnitCalcData) -> i32>),
}

#[derive(Clone, Copy)]
pub enum DivDirection {
    Horizontal,
    Vertical,
}

#[derive(Clone, Copy)]
pub enum DivAlignment {
    Min,
    Max,
    Center,
}

pub struct SpaceDiv {
    width: DivUnit,
    height: DivUnit,
    min_width: Option<DivUnit>,
    min_height: Option<DivUnit>,
    max_width: Option<DivUnit>,
    max_height: Option<DivUnit>,
    layout_dir: DivDirection,
    hori_align: DivAlignment,
    vert_align: DivAlignment,
    widget: Option<Box<Widget>>,
    child_divs: Vec<SpaceDiv>,
}

impl SpaceDiv {
    pub fn full() -> SpaceDivBuilder {
        SpaceDivBuilder::new()
            .width(DivUnit::Relative(1.0))
            .height(DivUnit::Relative(1.0))
    }

    // Compute the layout of the children.
    pub fn children(&self, self_bbox: Bbox) -> SpaceDivIter<::std::slice::Iter<SpaceDiv>> {
        let total_size = self.child_divs.iter().fold(Size::new(0, 0), |total, div| {
            total + div.size_pixels(self_bbox.size(), DivDirection::Vertical, Point::new(0, 0))
        });
        SpaceDivIter::new(
            self.child_divs.iter(),
            total_size,
            self_bbox,
            self.layout_dir,
            self.hori_align,
            self.vert_align,
        )
    }

    pub fn add_div(&mut self, div: SpaceDiv) {
        self.child_divs.push(div);
    }

    /// Compute this div's size in pixels.
    fn size_pixels(&self, parent_size: Size, parent_dir: DivDirection, last_origin: Point) -> Size {
        let calc_data = DivUnitCalcData {
            div: &self,
            direction: self.layout_dir,
            parent_size: parent_size,
            remaining: match parent_dir {
                DivDirection::Horizontal => max(parent_size.x - last_origin.x, 0),
                DivDirection::Vertical => max(parent_size.y - last_origin.y, 0),
            },
        };

        let w = match self.width {
            DivUnit::Pixels(pix) => pix,
            DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
            DivUnit::Calc(ref f) => (*f)(calc_data),
        };
        let h = match self.height {
            DivUnit::Pixels(pix) => pix,
            DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
            DivUnit::Calc(ref f) => (*f)(calc_data),
        };

        // Apply min and max width to width
        let w = if let Some(ref mw) = self.max_width {
            let mw = match *mw {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            min(w, mw)
        } else {
            w
        };

        let w = if let Some(ref mw) = self.min_width {
            let mw = match *mw {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.x as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            max(w, mw)
        } else {
            w
        };

        // Apply min and max height to height
        let h = if let Some(ref mh) = self.max_height {
            let mh = match *mh {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            min(h, mh)
        } else {
            h
        };

        let h = if let Some(ref mh) = self.min_height {
            let mh = match *mh {
                DivUnit::Pixels(pix) => pix,
                DivUnit::Relative(per) => (parent_size.y as f32 * per) as i32,
                DivUnit::Calc(ref f) => (*f)(calc_data),
            };
            max(h, mh)
        } else {
            h
        };

        Size::new(w, h)
    }
}

impl Default for SpaceDiv {
    fn default() -> Self {
        Self {
            width: DivUnit::Relative(1.0),
            height: DivUnit::Relative(1.0),
            min_width: None,
            min_height: None,
            max_width: None,
            max_height: None,
            layout_dir: DivDirection::Horizontal,
            hori_align: DivAlignment::Min,
            vert_align: DivAlignment::Min,
            widget: None,
            child_divs: Vec::new(),
        }
    }
}

/// Iterator that computes the positions and sizes of space divisions based on the
/// parent or containing bounding box.
/// This is essentially the layout engine.
pub struct SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    /// The space divisions to compute the layout of.
    space_divs: I,
    /// The sum total of all the space division sizes.
    total_size: Size,
    /// The containing (parent) bounding box.
    bbox: Bbox,
    /// The direction in with the layout grows.
    dir: DivDirection,
    /// The horizontal alignment.
    hori_align: DivAlignment,
    /// The vertical alignment.
    vert_align: DivAlignment,
    /// The current horizontal or vertical advance.
    cur: i32,
    /// The bottom-right coordinate of the last / previous division's bounding box.
    previous_end: Point,
}

impl<'a, I> SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    fn new(
        space_divs: I,
        total_size: Size,
        bbox: Bbox,
        dir: DivDirection,
        hori_align: DivAlignment,
        vert_align: DivAlignment,
    ) -> Self {
        Self {
            space_divs,
            total_size,
            bbox,
            dir,
            hori_align,
            vert_align,
            cur: 0,
            previous_end: Point::new(0, 0),
        }
    }
}

impl<'a, I> Iterator for SpaceDivIter<'a, I>
where
    I: Iterator<Item = &'a SpaceDiv>,
{
    type Item = (&'a SpaceDiv, Bbox);

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(div) = self.space_divs.next() {
            let size = div.size_pixels(self.bbox.size(), self.dir, self.previous_end);

            // Compute offset coordinates from top-left.
            let offset_x = match self.hori_align {
                DivAlignment::Min => 0,
                DivAlignment::Max => self.bbox.size().x - size.x,
                DivAlignment::Center => match self.dir {
                    DivDirection::Horizontal => self.bbox.size().x / 2 - self.total_size.x / 2,
                    DivDirection::Vertical => self.bbox.size().x / 2 - size.x / 2,
                },
            };
            let offset_y = match self.vert_align {
                DivAlignment::Min => 0,
                DivAlignment::Max => self.bbox.size().y - size.y,
                DivAlignment::Center => match self.dir {
                    DivDirection::Horizontal => self.bbox.size().y / 2 - size.y / 2,
                    DivDirection::Vertical => self.bbox.size().y / 2 - self.total_size.y / 2,
                },
            };

            let origin = match self.dir {
                DivDirection::Horizontal => {
                    Point::new(self.cur + offset_x, self.bbox.min.y + offset_y)
                }
                DivDirection::Vertical => {
                    Point::new(self.bbox.min.x + offset_x, self.cur + offset_y)
                }
            };
            self.previous_end = origin + size;

            let div_bbox = Bbox::with_size(origin, size);

            // Compute directions and advance.
            let dir_x = match self.hori_align {
                DivAlignment::Max => -1,
                _ => 1,
            };
            let dir_y = match self.vert_align {
                DivAlignment::Max => -1,
                _ => 1,
            };

            self.cur += match self.dir {
                DivDirection::Horizontal => size.x * dir_x,
                DivDirection::Vertical => size.y * dir_y,
            };

            Some((div, div_bbox))
        } else {
            None
        }
    }
}

pub struct SpaceDivBuilder {
    current: SpaceDiv,
}

impl SpaceDivBuilder {
    pub fn new() -> Self {
        Self {
            current: Default::default(),
        }
    }

    pub fn width(mut self, width: DivUnit) -> Self {
        self.current.width = width;
        self
    }

    pub fn height(mut self, height: DivUnit) -> Self {
        self.current.height = height;
        self
    }

    pub fn min_width(mut self, min_width: DivUnit) -> Self {
        self.current.min_width = Some(min_width);
        self
    }

    pub fn min_height(mut self, min_height: DivUnit) -> Self {
        self.current.min_height = Some(min_height);
        self
    }

    pub fn max_width(mut self, max_width: DivUnit) -> Self {
        self.current.max_width = Some(max_width);
        self
    }

    pub fn max_height(mut self, max_height: DivUnit) -> Self {
        self.current.max_height = Some(max_height);
        self
    }

    pub fn horizontal(mut self) -> Self {
        self.current.layout_dir = DivDirection::Horizontal;
        self
    }

    pub fn vertical(mut self) -> Self {
        self.current.layout_dir = DivDirection::Vertical;
        self
    }

    pub fn hori_align(mut self, hori_align: DivAlignment) -> Self {
        self.current.hori_align = hori_align;
        self
    }

    pub fn vert_align(mut self, vert_align: DivAlignment) -> Self {
        self.current.vert_align = vert_align;
        self
    }

    pub fn widget(mut self, widget: Box<Widget>) -> Self {
        self.current.widget = Some(widget);
        self
    }

    pub fn add_div(mut self, div: SpaceDiv) -> Self {
        self.current.add_div(div);
        self
    }

    pub fn build(self) -> SpaceDiv {
        self.current
    }
}
<|endoftext|>


<commit_before><commit_msg>Update new_for_testing.<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

extern crate libc;

use std::u64;
use time;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_ktime_getns()

/// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_KTIME_GETNS_IDX: u32 = 5;

/// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
/// let d =  t / 10u64.pow(9)  / 60   / 60  / 24;
/// let h = (t / 10u64.pow(9)  / 60   / 60) % 24;
/// let m = (t / 10u64.pow(9)  / 60 ) % 60;
/// let s = (t / 10u64.pow(9)) % 60;
/// let ns = t % 10u64.pow(9);
/// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_time_getns (unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    time::precise_time_ns()
}

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns the number of bytes written.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
/// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code needed to perform the call in this example would be nearly identical to the code
/// obtained by compiling the following code from C to eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
///     // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
///     char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    let size_arg = | x | {
        if x == 0 {
            1
        } else {
            (x as f64).log(16.0).floor() as u64 + 1
        }
    };
    "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
        + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}

// Some additional helpers

/// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
/// 5 are unused.
///
/// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
/// helper is used.
///
/// # Examples
///
/// ```
/// extern crate libc;
/// extern crate rbpf;
///
/// unsafe {
///     libc::srand(libc::time(std::ptr::null_mut()) as u32);
/// }
///
/// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
/// assert!(3 <= n && n <= 6);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn rand (min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    let mut n = unsafe {
        (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64
    };
    if min < max {
        n = n % (max + 1 - min) + min;
    };
    n
}
<commit_msg>Use time crate instead of libc<commit_after>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

extern crate libc;

use std::u64;
use time;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_ktime_getns()

/// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_KTIME_GETNS_IDX: u32 = 5;

/// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
/// let d =  t / 10u64.pow(9)  / 60   / 60  / 24;
/// let h = (t / 10u64.pow(9)  / 60   / 60) % 24;
/// let m = (t / 10u64.pow(9)  / 60 ) % 60;
/// let s = (t / 10u64.pow(9)) % 60;
/// let ns = t % 10u64.pow(9);
/// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_time_getns (unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    time::precise_time_ns()
}

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns the number of bytes written.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
/// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code needed to perform the call in this example would be nearly identical to the code
/// obtained by compiling the following code from C to eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
///     // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
///     char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    let size_arg = | x | {
        if x == 0 {
            1
        } else {
            (x as f64).log(16.0).floor() as u64 + 1
        }
    };
    "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
        + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}

// Some additional helpers

/// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
/// 5 are unused.
///
/// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
/// helper is used.
///
/// # Examples
///
/// ```
/// extern crate libc;
/// extern crate rbpf;
/// extern crate time;
///
/// unsafe {
///     libc::srand(time::precise_time_ns() as u32)
/// }
///
/// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
/// assert!(3 <= n && n <= 6);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn rand (min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    let mut n = unsafe {
        (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64
    };
    if min < max {
        n = n % (max + 1 - min) + min;
    };
    n
}
<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = if cfg!(unix) {
            unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
        } else {
            0
        };
        let f = File::create(path);
        if cfg!(unix) {
            unsafe {
                libc::umask(old_umask);
            }
        }
        let file = try!(f);
        if cfg!(unix) {
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

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

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Try to fix windows build<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = if cfg!(unix) {
            unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
        } else {
            0
        };
        let f = File::create(path);
        if cfg!(unix) {
            unsafe {
                libc::umask(old_umask);
            }
        }
        let file = try!(f);
        if cfg!(unix) {
            use std::os::unix::io::AsRawFd;
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

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

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %>

${helpers.single_keyword("dominant-baseline",
                 """auto use-script no-change reset-size ideographic alphabetic hanging
                    mathematical central middle text-after-edge text-before-edge""",
                 products="gecko",
                 animation_value_type="discrete",
                 spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty")}

${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")}

// Section 13 - Gradients and Patterns

${helpers.predefined_type(
    "stop-color", "RGBAColor",
    "RGBA::new(0, 0, 0, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty")}

${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
                          products="gecko",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")}

// Section 15 - Filter Effects

${helpers.predefined_type(
    "flood-color", "RGBAColor",
    "RGBA::new(0, 0, 0, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty")}

${helpers.predefined_type("flood-opacity", "Opacity",
                          "1.0", products="gecko", animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}

${helpers.predefined_type(
    "lighting-color", "RGBAColor",
    "RGBA::new(255, 255, 255, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVG/filters.html#LightingColorProperty")}

// CSS Masking Module Level 1
// https://drafts.fxtf.org/css-masking
${helpers.single_keyword("mask-type", "luminance alpha",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}

${helpers.predefined_type("clip-path", "basic_shape::ClippingShape",
                          "generics::basic_shape::ShapeSource::None",
                          products="gecko", boxed="True",
                          animation_value_type="none", flags="CREATES_STACKING_CONTEXT",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path")}

${helpers.single_keyword("mask-mode",
                         "match-source alpha luminance",
                         vector=True,
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode")}

<%helpers:vector_longhand name="mask-repeat" products="gecko" animation_value_type="none" extra_prefixes="webkit"
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-repeat">
    pub use properties::longhands::background_repeat::single_value::parse;
    pub use properties::longhands::background_repeat::single_value::SpecifiedValue;
    pub use properties::longhands::background_repeat::single_value::computed_value;
    pub use properties::longhands::background_repeat::single_value::RepeatKeyword;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(RepeatKeyword::Repeat, RepeatKeyword::Repeat)
    }

    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue::Other(RepeatKeyword::Repeat, None)
    }
</%helpers:vector_longhand>

% for (axis, direction) in [("x", "Horizontal"), ("y", "Vertical")]:
    ${helpers.predefined_type("mask-position-" + axis, "position::" + direction + "Position",
                              products="gecko", extra_prefixes="webkit",
                              initial_value="computed::LengthOrPercentage::zero()",
                              initial_specified_value="specified::PositionComponent::Center",
                              spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
                              animation_value_type="ComputedValue", vector=True, delegate_animate=True)}
% endfor

${helpers.single_keyword("mask-clip",
                         "border-box content-box padding-box",
                         extra_gecko_values="fill-box stroke-box view-box no-clip",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         gecko_enum_prefix="StyleGeometryBox",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-clip")}

${helpers.single_keyword("mask-origin",
                         "border-box content-box padding-box",
                         extra_gecko_values="fill-box stroke-box view-box",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         gecko_enum_prefix="StyleGeometryBox",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}

<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit"
                   spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size">
    use properties::longhands::background_size;
    pub use ::properties::longhands::background_size::SpecifiedValue;
    pub use ::properties::longhands::background_size::single_value as single_value;
    pub use ::properties::longhands::background_size::computed_value as computed_value;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        background_size::get_initial_value()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        background_size::parse(context, input)
    }
</%helpers:longhand>

${helpers.single_keyword("mask-composite",
                         "add subtract intersect exclude",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}

${helpers.predefined_type("mask-image", "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
    vector=True,
    products="gecko",
    extra_prefixes="webkit",
    animation_value_type="none",
    flags="CREATES_STACKING_CONTEXT",
    has_uncacheable_values="True" if product == "gecko" else "False")}
<commit_msg>Auto merge of #17251 - chenpighead:stylo-stop-flood-opacity-animatable, r=hiro<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %>

${helpers.single_keyword("dominant-baseline",
                 """auto use-script no-change reset-size ideographic alphabetic hanging
                    mathematical central middle text-after-edge text-before-edge""",
                 products="gecko",
                 animation_value_type="discrete",
                 spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty")}

${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")}

// Section 13 - Gradients and Patterns

${helpers.predefined_type(
    "stop-color", "RGBAColor",
    "RGBA::new(0, 0, 0, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty")}

${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
                          products="gecko",
                          animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")}

// Section 15 - Filter Effects

${helpers.predefined_type(
    "flood-color", "RGBAColor",
    "RGBA::new(0, 0, 0, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty")}

${helpers.predefined_type("flood-opacity", "Opacity",
                          "1.0", products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}

${helpers.predefined_type(
    "lighting-color", "RGBAColor",
    "RGBA::new(255, 255, 255, 255)",
    products="gecko",
    animation_value_type="none",
    spec="https://www.w3.org/TR/SVG/filters.html#LightingColorProperty")}

// CSS Masking Module Level 1
// https://drafts.fxtf.org/css-masking
${helpers.single_keyword("mask-type", "luminance alpha",
                         products="gecko", animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}

${helpers.predefined_type("clip-path", "basic_shape::ClippingShape",
                          "generics::basic_shape::ShapeSource::None",
                          products="gecko", boxed="True",
                          animation_value_type="none", flags="CREATES_STACKING_CONTEXT",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path")}

${helpers.single_keyword("mask-mode",
                         "match-source alpha luminance",
                         vector=True,
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode")}

<%helpers:vector_longhand name="mask-repeat" products="gecko" animation_value_type="none" extra_prefixes="webkit"
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-repeat">
    pub use properties::longhands::background_repeat::single_value::parse;
    pub use properties::longhands::background_repeat::single_value::SpecifiedValue;
    pub use properties::longhands::background_repeat::single_value::computed_value;
    pub use properties::longhands::background_repeat::single_value::RepeatKeyword;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(RepeatKeyword::Repeat, RepeatKeyword::Repeat)
    }

    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue::Other(RepeatKeyword::Repeat, None)
    }
</%helpers:vector_longhand>

% for (axis, direction) in [("x", "Horizontal"), ("y", "Vertical")]:
    ${helpers.predefined_type("mask-position-" + axis, "position::" + direction + "Position",
                              products="gecko", extra_prefixes="webkit",
                              initial_value="computed::LengthOrPercentage::zero()",
                              initial_specified_value="specified::PositionComponent::Center",
                              spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
                              animation_value_type="ComputedValue", vector=True, delegate_animate=True)}
% endfor

${helpers.single_keyword("mask-clip",
                         "border-box content-box padding-box",
                         extra_gecko_values="fill-box stroke-box view-box no-clip",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         gecko_enum_prefix="StyleGeometryBox",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-clip")}

${helpers.single_keyword("mask-origin",
                         "border-box content-box padding-box",
                         extra_gecko_values="fill-box stroke-box view-box",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         gecko_enum_prefix="StyleGeometryBox",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}

<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit"
                   spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size">
    use properties::longhands::background_size;
    pub use ::properties::longhands::background_size::SpecifiedValue;
    pub use ::properties::longhands::background_size::single_value as single_value;
    pub use ::properties::longhands::background_size::computed_value as computed_value;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        background_size::get_initial_value()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        background_size::parse(context, input)
    }
</%helpers:longhand>

${helpers.single_keyword("mask-composite",
                         "add subtract intersect exclude",
                         vector=True,
                         products="gecko",
                         extra_prefixes="webkit",
                         animation_value_type="discrete",
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}

${helpers.predefined_type("mask-image", "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
    vector=True,
    products="gecko",
    extra_prefixes="webkit",
    animation_value_type="none",
    flags="CREATES_STACKING_CONTEXT",
    has_uncacheable_values="True" if product == "gecko" else "False")}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword(
    "ime-mode",
    "auto normal active disabled inactive",
    engines="gecko",
    gecko_ffi_name="mIMEMode",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ui/#input-method-editor",
)}

${helpers.single_keyword(
    "scrollbar-width",
    "auto thin none",
    engines="gecko",
    gecko_enum_prefix="StyleScrollbarWidth",
    animation_value_type="discrete",
    gecko_pref="layout.css.scrollbar-width.enabled",
    enabled_in="chrome",
    spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width"
)}

${helpers.predefined_type(
    "user-select",
    "UserSelect",
    "computed::UserSelect::Auto",
    engines="gecko",
    extra_prefixes="moz webkit",
    animation_value_type="discrete",
    needs_context=False,
    spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
)}

// TODO(emilio): This probably should be hidden from content.
${helpers.single_keyword(
    "-moz-window-dragging",
    "default drag no-drag",
    engines="gecko",
    gecko_ffi_name="mWindowDragging",
    gecko_enum_prefix="StyleWindowDragging",
    animation_value_type="discrete",
    spec="None (Nonstandard Firefox-only property)",
)}

${helpers.single_keyword(
    "-moz-window-shadow",
    "none default menu tooltip sheet",
    engines="gecko",
    gecko_ffi_name="mWindowShadow",
    gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
    animation_value_type="discrete",
    enabled_in="chrome",
    spec="None (Nonstandard internal property)",
)}

${helpers.predefined_type(
    "-moz-window-opacity",
    "Opacity",
    "1.0",
    engines="gecko",
    gecko_ffi_name="mWindowOpacity",
    animation_value_type="ComputedValue",
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

${helpers.predefined_type(
    "-moz-window-transform",
    "Transform",
    "generics::transform::Transform::none()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

${helpers.predefined_type(
    "-moz-window-transform-origin",
    "TransformOrigin",
    "computed::TransformOrigin::initial_value()",
    engines="gecko",
    animation_value_type="ComputedValue",
    gecko_ffi_name="mWindowTransformOrigin",
    boxed=True,
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type(
    "-moz-force-broken-image-icon",
    "MozForceBrokenImageIcon",
    "computed::MozForceBrokenImageIcon::false_value()",
    engines="gecko",
    animation_value_type="discrete",
    spec="None (Nonstandard Firefox-only property)",
)}
<commit_msg>style: convert NS_STYLE_IME_MODE_* to an enum class in nsStyleConsts.h<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>

// CSS Basic User Interface Module Level 1
// https://drafts.csswg.org/css-ui-3/
<% data.new_style_struct("UI", inherited=False, gecko_name="UIReset") %>

// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword(
    "ime-mode",
    "auto normal active disabled inactive",
    engines="gecko",
    gecko_enum_prefix="StyleImeMode",
    gecko_ffi_name="mIMEMode",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ui/#input-method-editor",
)}

${helpers.single_keyword(
    "scrollbar-width",
    "auto thin none",
    engines="gecko",
    gecko_enum_prefix="StyleScrollbarWidth",
    animation_value_type="discrete",
    gecko_pref="layout.css.scrollbar-width.enabled",
    enabled_in="chrome",
    spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width"
)}

${helpers.predefined_type(
    "user-select",
    "UserSelect",
    "computed::UserSelect::Auto",
    engines="gecko",
    extra_prefixes="moz webkit",
    animation_value_type="discrete",
    needs_context=False,
    spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
)}

// TODO(emilio): This probably should be hidden from content.
${helpers.single_keyword(
    "-moz-window-dragging",
    "default drag no-drag",
    engines="gecko",
    gecko_ffi_name="mWindowDragging",
    gecko_enum_prefix="StyleWindowDragging",
    animation_value_type="discrete",
    spec="None (Nonstandard Firefox-only property)",
)}

${helpers.single_keyword(
    "-moz-window-shadow",
    "none default menu tooltip sheet",
    engines="gecko",
    gecko_ffi_name="mWindowShadow",
    gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
    animation_value_type="discrete",
    enabled_in="chrome",
    spec="None (Nonstandard internal property)",
)}

${helpers.predefined_type(
    "-moz-window-opacity",
    "Opacity",
    "1.0",
    engines="gecko",
    gecko_ffi_name="mWindowOpacity",
    animation_value_type="ComputedValue",
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

${helpers.predefined_type(
    "-moz-window-transform",
    "Transform",
    "generics::transform::Transform::none()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

${helpers.predefined_type(
    "-moz-window-transform-origin",
    "TransformOrigin",
    "computed::TransformOrigin::initial_value()",
    engines="gecko",
    animation_value_type="ComputedValue",
    gecko_ffi_name="mWindowTransformOrigin",
    boxed=True,
    spec="None (Nonstandard internal property)",
    enabled_in="chrome",
)}

// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type(
    "-moz-force-broken-image-icon",
    "MozForceBrokenImageIcon",
    "computed::MozForceBrokenImageIcon::false_value()",
    engines="gecko",
    animation_value_type="discrete",
    spec="None (Nonstandard Firefox-only property)",
)}
<|endoftext|>


<commit_before><commit_msg>remove sync requirement on Context<commit_after><|endoftext|>


<commit_before>extern crate regex;

use super::super::*;
use std::io::BufReader;
use self::regex::Regex;
pub static PROVIDER: &'static Provider = &ChanEngine;

struct ChanEngine;

#[derive(Deserialize)]
struct Data {
    boards: Vec<String>,
    filters: Vec<String>,
}

type Catalog = Vec<Page>;

#[derive(Deserialize)]
struct Page {
    page: i32,
    threads: Vec<OP>,
}

#[derive(Deserialize, Clone)]
struct OP {
    no: i32,
    time: u64,
    sub: Option<String>,
    com: Option<String>,
    tim: Option<u64>,
    ext: Option<String>,
    replies: i32,
    images: i32,
    semantic_url: String,
}

#[derive(Serialize)]
struct OPExtra {
    replies: i32,
    images: i32,
    page: i32,
    board: String,
}

impl Provider for ChanEngine {
    fn load_feed(&self, data: &Json) -> Result<Feed, Box<Error>> {
        let mut feed = Feed::new();
        let data: Data = try!(serde_json::from_value(data.clone()));

        let wrapped_filters = data.filters.iter()
                .map(|filter| Regex::new(filter));
        let mut filters = Vec::new();

        for filter in wrapped_filters {
            filters.push(try!(filter));
        }

        for board in &data.boards {
            let url = format!("http://a.4cdn.org/{}/catalog.json", board);
            let catalog: Catalog = try!(serde_json::from_slice(&try!(http_get(&url))));
            for page in catalog {
                for op in page.threads {
                    if !filters.iter().any(|f| f.is_match(op.sub.as_ref().unwrap_or(&"".to_string())) || f.is_match(op.com.as_ref().unwrap_or(&"".to_string()))) {
                        continue;
                    }
                    let extra = serde_json::to_value(OPExtra{
                        replies: op.replies,
                        images: op.images,
                        page: page.page,
                        board: board.clone(),
                    });
                    let mut entry = Entry::new(&op.sub.unwrap_or(op.semantic_url), &hash(&(op.no, board)))
                            .set_description(op.com)
                            .link(&format!("https://boards.4chan.org/{}/thread/{}", board, op.no))
                            .timestamp(op.time as u64)
                            .extra(extra);
                    if let (Some(tim), Some(ext)) = (op.tim, op.ext) {
                        entry = entry.image_url(&format!("https://i.4cdn.org/{}/{}{}", board, tim, ext));
                    }
                    feed.status.push(entry);
                }
            }
        }

        Ok(feed)
    }
}
<commit_msg>Fixed titles having `-` instead of spaces in OPs<commit_after>extern crate regex;

use super::super::*;
use std::io::BufReader;
use self::regex::Regex;
pub static PROVIDER: &'static Provider = &ChanEngine;

struct ChanEngine;

#[derive(Deserialize)]
struct Data {
    boards: Vec<String>,
    filters: Vec<String>,
}

type Catalog = Vec<Page>;

#[derive(Deserialize)]
struct Page {
    page: i32,
    threads: Vec<OP>,
}

#[derive(Deserialize, Clone)]
struct OP {
    no: i32,
    time: u64,
    sub: Option<String>,
    com: Option<String>,
    tim: Option<u64>,
    ext: Option<String>,
    replies: i32,
    images: i32,
    semantic_url: String,
}

#[derive(Serialize)]
struct OPExtra {
    replies: i32,
    images: i32,
    page: i32,
    board: String,
}

impl Provider for ChanEngine {
    fn load_feed(&self, data: &Json) -> Result<Feed, Box<Error>> {
        let mut feed = Feed::new();
        let data: Data = try!(serde_json::from_value(data.clone()));

        let wrapped_filters = data.filters.iter()
                .map(|filter| Regex::new(filter));
        let mut filters = Vec::new();

        for filter in wrapped_filters {
            filters.push(try!(filter));
        }

        for board in &data.boards {
            let url = format!("http://a.4cdn.org/{}/catalog.json", board);
            let catalog: Catalog = try!(serde_json::from_slice(&try!(http_get(&url))));
            for page in catalog {
                for op in page.threads {
                    if !filters.iter().any(|f| f.is_match(op.sub.as_ref().unwrap_or(&"".to_string())) || f.is_match(op.com.as_ref().unwrap_or(&"".to_string()))) {
                        continue;
                    }
                    let extra = serde_json::to_value(OPExtra{
                        replies: op.replies,
                        images: op.images,
                        page: page.page,
                        board: board.clone(),
                    });
                    let mut entry = Entry::new(&op.sub.unwrap_or(op.semantic_url.replace("-", " ")), &hash(&(op.no, board)))
                            .set_description(op.com)
                            .link(&format!("https://boards.4chan.org/{}/thread/{}", board, op.no))
                            .timestamp(op.time as u64)
                            .extra(extra);
                    if let (Some(tim), Some(ext)) = (op.tim, op.ext) {
                        entry = entry.image_url(&format!("https://i.4cdn.org/{}/{}{}", board, tim, ext));
                    }
                    feed.status.push(entry);
                }
            }
        }

        Ok(feed)
    }
}
<|endoftext|>


<commit_before>
extern crate lapack;

use self::lapack::fortran::*;
use error::LapackError;
use ndarray::LinalgScalar;

pub trait LapackScalar: LinalgScalar {
    fn syev(jobz: u8,
            uplo: u8,
            n: i32,
            a: &mut Vec<Self>,
            lda: i32,
            w: &mut Vec<Self>,
            work: &mut Vec<Self>,
            lwork: i32,
            info: &mut i32);
    fn getrf(m: i32, n: i32, a: &mut Vec<Self>, lda: i32, ipiv: &mut [i32], info: &mut i32);
    fn getri(n: i32,
             a: &mut Vec<Self>,
             lda: i32,
             ipiv: &[i32],
             work: &mut Vec<Self>,
             lwork: i32,
             info: &mut i32);
    fn lange(norm: u8, m: i32, n: i32, a: &Vec<Self>, lda: i32, work: &mut Vec<Self>) -> Self;

    fn eigh(n: usize, mut a: Vec<Self>) -> Result<(Vec<Self>, Vec<Self>), LapackError> {
        let mut w = vec![Self::zero(); n];
        let mut work = vec![Self::zero(); 4 * n];
        let mut info = 0;
        Self::syev(b'V',
                   b'U',
                   n as i32,
                   &mut a,
                   n as i32,
                   &mut w,
                   &mut work,
                   4 * n as i32,
                   &mut info);
        if info == 0 {
            Ok((w, a))
        } else {
            Err(From::from(info))
        }
    }
    fn inv(size: usize, mut a: Vec<Self>) -> Result<Vec<Self>, LapackError> {
        let n = size as i32;
        let lda = n;
        let mut ipiv = vec![0; size];
        let mut info = 0;
        Self::getrf(n, n, &mut a, lda, &mut ipiv, &mut info);
        if info != 0 {
            return Err(From::from(info));
        }
        let lwork = n;
        let mut work = vec![Self::zero(); size];
        Self::getri(n, &mut a, lda, &mut ipiv, &mut work, lwork, &mut info);
        if info == 0 {
            Ok(a)
        } else {
            Err(From::from(info))
        }
    }
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        Self::lange(b'o', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = vec![Self::zero(); m];
        Self::lange(b'i', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        Self::lange(b'f', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
}

impl LapackScalar for f64 {
    fn syev(jobz: u8,
            uplo: u8,
            n: i32,
            a: &mut Vec<Self>,
            lda: i32,
            w: &mut Vec<Self>,
            work: &mut Vec<Self>,
            lwork: i32,
            info: &mut i32) {
        dsyev(jobz, uplo, n, a, lda, w, work, lwork, info);
    }
    fn getrf(m: i32, n: i32, a: &mut Vec<Self>, lda: i32, ipiv: &mut [i32], info: &mut i32) {
        dgetrf(m, n, a, lda, ipiv, info);
    }
    fn getri(n: i32,
             a: &mut Vec<Self>,
             lda: i32,
             ipiv: &[i32],
             work: &mut Vec<Self>,
             lwork: i32,
             info: &mut i32) {
        dgetri(n, a, lda, ipiv, work, lwork, info);
    }
    fn lange(norm: u8, m: i32, n: i32, a: &Vec<Self>, lda: i32, work: &mut Vec<Self>) -> Self {
        dlange(norm, m, n, a, lda, work)
    }
}
<commit_msg>Add f32 binding<commit_after>
extern crate lapack;

use self::lapack::fortran::*;
use error::LapackError;
use ndarray::LinalgScalar;

pub trait LapackScalar: LinalgScalar {
    fn _syev(jobz: u8,
             uplo: u8,
             n: i32,
             a: &mut Vec<Self>,
             lda: i32,
             w: &mut Vec<Self>,
             work: &mut Vec<Self>,
             lwork: i32,
             info: &mut i32);
    fn _getrf(m: i32, n: i32, a: &mut Vec<Self>, lda: i32, ipiv: &mut [i32], info: &mut i32);
    fn _getri(n: i32,
              a: &mut Vec<Self>,
              lda: i32,
              ipiv: &[i32],
              work: &mut Vec<Self>,
              lwork: i32,
              info: &mut i32);
    fn _lange(norm: u8, m: i32, n: i32, a: &Vec<Self>, lda: i32, work: &mut Vec<Self>) -> Self;

    fn eigh(n: usize, mut a: Vec<Self>) -> Result<(Vec<Self>, Vec<Self>), LapackError> {
        let mut w = vec![Self::zero(); n];
        let mut work = vec![Self::zero(); 4 * n];
        let mut info = 0;
        Self::_syev(b'V',
                    b'U',
                    n as i32,
                    &mut a,
                    n as i32,
                    &mut w,
                    &mut work,
                    4 * n as i32,
                    &mut info);
        if info == 0 {
            Ok((w, a))
        } else {
            Err(From::from(info))
        }
    }
    fn inv(size: usize, mut a: Vec<Self>) -> Result<Vec<Self>, LapackError> {
        let n = size as i32;
        let lda = n;
        let mut ipiv = vec![0; size];
        let mut info = 0;
        Self::_getrf(n, n, &mut a, lda, &mut ipiv, &mut info);
        if info != 0 {
            return Err(From::from(info));
        }
        let lwork = n;
        let mut work = vec![Self::zero(); size];
        Self::_getri(n, &mut a, lda, &mut ipiv, &mut work, lwork, &mut info);
        if info == 0 {
            Ok(a)
        } else {
            Err(From::from(info))
        }
    }
    fn norm_1(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        Self::_lange(b'o', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_i(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = vec![Self::zero(); m];
        Self::_lange(b'i', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
    fn norm_f(m: usize, n: usize, mut a: Vec<Self>) -> Self {
        let mut work = Vec::<Self>::new();
        Self::_lange(b'f', m as i32, n as i32, &mut a, m as i32, &mut work)
    }
}

impl LapackScalar for f64 {
    fn _syev(jobz: u8,
             uplo: u8,
             n: i32,
             a: &mut Vec<Self>,
             lda: i32,
             w: &mut Vec<Self>,
             work: &mut Vec<Self>,
             lwork: i32,
             info: &mut i32) {
        dsyev(jobz, uplo, n, a, lda, w, work, lwork, info);
    }
    fn _getrf(m: i32, n: i32, a: &mut Vec<Self>, lda: i32, ipiv: &mut [i32], info: &mut i32) {
        dgetrf(m, n, a, lda, ipiv, info);
    }
    fn _getri(n: i32,
              a: &mut Vec<Self>,
              lda: i32,
              ipiv: &[i32],
              work: &mut Vec<Self>,
              lwork: i32,
              info: &mut i32) {
        dgetri(n, a, lda, ipiv, work, lwork, info);
    }
    fn _lange(norm: u8, m: i32, n: i32, a: &Vec<Self>, lda: i32, work: &mut Vec<Self>) -> Self {
        dlange(norm, m, n, a, lda, work)
    }
}

impl LapackScalar for f32 {
    fn _syev(jobz: u8,
             uplo: u8,
             n: i32,
             a: &mut Vec<Self>,
             lda: i32,
             w: &mut Vec<Self>,
             work: &mut Vec<Self>,
             lwork: i32,
             info: &mut i32) {
        ssyev(jobz, uplo, n, a, lda, w, work, lwork, info);
    }
    fn _getrf(m: i32, n: i32, a: &mut Vec<Self>, lda: i32, ipiv: &mut [i32], info: &mut i32) {
        sgetrf(m, n, a, lda, ipiv, info);
    }
    fn _getri(n: i32,
              a: &mut Vec<Self>,
              lda: i32,
              ipiv: &[i32],
              work: &mut Vec<Self>,
              lwork: i32,
              info: &mut i32) {
        sgetri(n, a, lda, ipiv, work, lwork, info);
    }
    fn _lange(norm: u8, m: i32, n: i32, a: &Vec<Self>, lda: i32, work: &mut Vec<Self>) -> Self {
        slange(norm, m, n, a, lda, work)
    }
}
<|endoftext|>