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

use frame_builder::FrameBuilder;
use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, PrimitiveContainer};
use tiling::PrimitiveFlags;
use util::pack_as_float;
use webrender_traits::{BorderSide, BorderStyle, BorderWidths, ColorF, NormalBorder};
use webrender_traits::{ClipId, ClipRegion, LayerPoint, LayerRect, LayerSize};

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderCornerKind {
    None,
    Solid,
    Clip,
    Unhandled,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderEdgeKind {
    None,
    Solid,
    Unhandled,
}

pub trait NormalBorderHelpers {
    fn get_corner(&self,
                  edge0: &BorderSide,
                  width0: f32,
                  edge1: &BorderSide,
                  width1: f32,
                  radius: &LayerSize) -> BorderCornerKind;

    fn get_edge(&self,
                edge: &BorderSide,
                width: f32) -> (BorderEdgeKind, f32);
}

impl NormalBorderHelpers for NormalBorder {
    fn get_corner(&self,
                  edge0: &BorderSide,
                  width0: f32,
                  edge1: &BorderSide,
                  width1: f32,
                  radius: &LayerSize) -> BorderCornerKind {
        // If either width is zero, a corner isn't formed.
        if width0 == 0.0 || width1 == 0.0 {
            return BorderCornerKind::None;
        }

        // If both edges are transparent, no corner is formed.
        if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
            return BorderCornerKind::None;
        }

        match (edge0.style, edge1.style) {
            // If either edge is none or hidden, no corner is needed.
            (BorderStyle::None, _) | (_, BorderStyle::None) => BorderCornerKind::None,
            (BorderStyle::Hidden, _) | (_, BorderStyle::Hidden) => BorderCornerKind::None,

            // If both borders are solid, we can draw them with a simple rectangle if
            // both the colors match and there is no radius.
            (BorderStyle::Solid, BorderStyle::Solid) => {
                if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
                    BorderCornerKind::Solid
                } else {
                    BorderCornerKind::Clip
                }
            }

            // Assume complex for these cases.
            // TODO(gw): There are some cases in here that can be handled with a fast path.
            // For example, with inset/outset borders, two of the four corners are solid.
            (BorderStyle::Dotted, _) | (_, BorderStyle::Dotted) => BorderCornerKind::Unhandled,
            (BorderStyle::Dashed, _) | (_, BorderStyle::Dashed) => BorderCornerKind::Unhandled,
            (BorderStyle::Double, _) | (_, BorderStyle::Double) => BorderCornerKind::Unhandled,
            (BorderStyle::Groove, _) | (_, BorderStyle::Groove) => BorderCornerKind::Unhandled,
            (BorderStyle::Ridge, _) | (_, BorderStyle::Ridge) => BorderCornerKind::Unhandled,
            (BorderStyle::Outset, _) | (_, BorderStyle::Outset) => BorderCornerKind::Unhandled,
            (BorderStyle::Inset, _) | (_, BorderStyle::Inset) => BorderCornerKind::Unhandled,
        }
    }

    fn get_edge(&self,
                edge: &BorderSide,
                width: f32) -> (BorderEdgeKind, f32) {
        if width == 0.0 {
            return (BorderEdgeKind::None, 0.0);
        }

        match edge.style {
            BorderStyle::None |
            BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),

            BorderStyle::Solid |
            BorderStyle::Inset |
            BorderStyle::Outset => (BorderEdgeKind::Solid, width),

            BorderStyle::Double |
            BorderStyle::Dotted |
            BorderStyle::Dashed |
            BorderStyle::Groove |
            BorderStyle::Ridge => (BorderEdgeKind::Unhandled, width),
        }
    }
}

impl FrameBuilder {
    fn add_normal_border_primitive(&mut self,
                                   rect: &LayerRect,
                                   border: &NormalBorder,
                                   widths: &BorderWidths,
                                   clip_id: ClipId,
                                   clip_region: &ClipRegion,
                                   use_new_border_path: bool) {
        let radius = &border.radius;
        let left = &border.left;
        let right = &border.right;
        let top = &border.top;
        let bottom = &border.bottom;

        // These colors are used during inset/outset scaling.
        let left_color      = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
        let top_color       = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
        let right_color     = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
        let bottom_color    = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);

        let prim_cpu = BorderPrimitiveCpu {
            use_new_border_path: use_new_border_path,
        };

        let prim_gpu = BorderPrimitiveGpu {
            colors: [ left_color, top_color, right_color, bottom_color ],
            widths: [ widths.left,
                      widths.top,
                      widths.right,
                      widths.bottom ],
            style: [
                pack_as_float(left.style as u32),
                pack_as_float(top.style as u32),
                pack_as_float(right.style as u32),
                pack_as_float(bottom.style as u32),
            ],
            radii: [
                radius.top_left,
                radius.top_right,
                radius.bottom_right,
                radius.bottom_left,
            ],
        };

        self.add_primitive(clip_id,
                           &rect,
                           clip_region,
                           &[],
                           PrimitiveContainer::Border(prim_cpu, prim_gpu));
    }

    // TODO(gw): This allows us to move border types over to the
    // simplified shader model one at a time. Once all borders
    // are converted, this can be removed, along with the complex
    // border code path.
    pub fn add_normal_border(&mut self,
                             rect: &LayerRect,
                             border: &NormalBorder,
                             widths: &BorderWidths,
                             clip_id: ClipId,
                             clip_region: &ClipRegion) {
        // The border shader is quite expensive. For simple borders, we can just draw
        // the border with a few rectangles. This generally gives better batching, and
        // a GPU win in fragment shader time.
        // More importantly, the software (OSMesa) implementation we run tests on is
        // particularly slow at running our complex border shader, compared to the
        // rectangle shader. This has the effect of making some of our tests time
        // out more often on CI (the actual cause is simply too many Servo processes and
        // threads being run on CI at once).

        let radius = &border.radius;
        let left = &border.left;
        let right = &border.right;
        let top = &border.top;
        let bottom = &border.bottom;

        let corners = [
            border.get_corner(left, widths.left, top, widths.top, &radius.top_left),
            border.get_corner(top, widths.top, right, widths.right, &radius.top_right),
            border.get_corner(right, widths.right, bottom, widths.bottom, &radius.bottom_right),
            border.get_corner(bottom, widths.bottom, left, widths.left, &radius.bottom_left),
        ];

        // If any of the corners are unhandled, fall back to slow path for now.
        if corners.iter().any(|c| *c == BorderCornerKind::Unhandled) {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             false);
            return;
        }

        let (left_edge, left_len) = border.get_edge(left, widths.left);
        let (top_edge, top_len) = border.get_edge(top, widths.top);
        let (right_edge, right_len) = border.get_edge(right, widths.right);
        let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom);

        let edges = [
            left_edge,
            top_edge,
            right_edge,
            bottom_edge,
        ];

        // If any of the edges are unhandled, fall back to slow path for now.
        if edges.iter().any(|e| *e == BorderEdgeKind::Unhandled) {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             false);
            return;
        }

        // Use a simple rectangle case when all edges and corners are either
        // solid or none.
        let all_corners_simple = corners.iter().all(|c| {
            *c == BorderCornerKind::Solid || *c == BorderCornerKind::None
        });
        let all_edges_simple = edges.iter().all(|e| {
            *e == BorderEdgeKind::Solid || *e == BorderEdgeKind::None
        });

        if all_corners_simple && all_edges_simple {
            let p0 = rect.origin;
            let p1 = rect.bottom_right();
            let rect_width = rect.size.width;
            let rect_height = rect.size.height;

            // Add a solid rectangle for each visible edge/corner combination.
            if top_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(p0,
                                                         LayerSize::new(rect_width, top_len)),
                                         clip_region,
                                         &border.top.color,
                                         PrimitiveFlags::None);
            }
            if left_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p0.x, p0.y + top_len),
                                                         LayerSize::new(left_len,
                                                                        rect_height - top_len - bottom_len)),
                                         clip_region,
                                         &border.left.color,
                                         PrimitiveFlags::None);
            }
            if right_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p1.x - right_len,
                                                                         p0.y + top_len),
                                                         LayerSize::new(right_len,
                                                                        rect_height - top_len - bottom_len)),
                                         clip_region,
                                         &border.right.color,
                                         PrimitiveFlags::None);
            }
            if bottom_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p0.x, p1.y - bottom_len),
                                                         LayerSize::new(rect_width, bottom_len)),
                                         clip_region,
                                         &border.bottom.color,
                                         PrimitiveFlags::None);
            }
        } else {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             true);
        }
    }
}

pub trait BorderSideHelpers {
    fn border_color(&self,
                    scale_factor_0: f32,
                    scale_factor_1: f32,
                    black_color_0: f32,
                    black_color_1: f32) -> ColorF;
}

impl BorderSideHelpers for BorderSide {
    fn border_color(&self,
                    scale_factor_0: f32,
                    scale_factor_1: f32,
                    black_color_0: f32,
                    black_color_1: f32) -> ColorF {
        match self.style {
            BorderStyle::Inset => {
                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
                    self.color.scale_rgb(scale_factor_1)
                } else {
                    ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
                }
            }
            BorderStyle::Outset => {
                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
                    self.color.scale_rgb(scale_factor_0)
                } else {
                    ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
                }
            }
            _ => self.color,
        }
    }
}
<commit_msg>Whitelist inset/outset borders for new border path.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use frame_builder::FrameBuilder;
use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, PrimitiveContainer};
use tiling::PrimitiveFlags;
use util::pack_as_float;
use webrender_traits::{BorderSide, BorderStyle, BorderWidths, ColorF, NormalBorder};
use webrender_traits::{ClipId, ClipRegion, LayerPoint, LayerRect, LayerSize};

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderCornerKind {
    None,
    Solid,
    Clip,
    Unhandled,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderEdgeKind {
    None,
    Solid,
    Unhandled,
}

pub trait NormalBorderHelpers {
    fn get_corner(&self,
                  edge0: &BorderSide,
                  width0: f32,
                  edge1: &BorderSide,
                  width1: f32,
                  radius: &LayerSize) -> BorderCornerKind;

    fn get_edge(&self,
                edge: &BorderSide,
                width: f32) -> (BorderEdgeKind, f32);
}

impl NormalBorderHelpers for NormalBorder {
    fn get_corner(&self,
                  edge0: &BorderSide,
                  width0: f32,
                  edge1: &BorderSide,
                  width1: f32,
                  radius: &LayerSize) -> BorderCornerKind {
        // If either width is zero, a corner isn't formed.
        if width0 == 0.0 || width1 == 0.0 {
            return BorderCornerKind::None;
        }

        // If both edges are transparent, no corner is formed.
        if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
            return BorderCornerKind::None;
        }

        match (edge0.style, edge1.style) {
            // If either edge is none or hidden, no corner is needed.
            (BorderStyle::None, _) | (_, BorderStyle::None) => BorderCornerKind::None,
            (BorderStyle::Hidden, _) | (_, BorderStyle::Hidden) => BorderCornerKind::None,

            // If both borders are solid, we can draw them with a simple rectangle if
            // both the colors match and there is no radius.
            (BorderStyle::Solid, BorderStyle::Solid) => {
                if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
                    BorderCornerKind::Solid
                } else {
                    BorderCornerKind::Clip
                }
            }

            // Inset / outset borders just modtify the color of edges, so can be
            // drawn with the normal border corner shader.
            (BorderStyle::Outset, BorderStyle::Outset) |
            (BorderStyle::Inset, BorderStyle::Inset) => BorderCornerKind::Clip,

            // Assume complex for these cases.
            // TODO(gw): There are some cases in here that can be handled with a fast path.
            // For example, with inset/outset borders, two of the four corners are solid.
            (BorderStyle::Dotted, _) | (_, BorderStyle::Dotted) => BorderCornerKind::Unhandled,
            (BorderStyle::Dashed, _) | (_, BorderStyle::Dashed) => BorderCornerKind::Unhandled,
            (BorderStyle::Double, _) | (_, BorderStyle::Double) => BorderCornerKind::Unhandled,
            (BorderStyle::Groove, _) | (_, BorderStyle::Groove) => BorderCornerKind::Unhandled,
            (BorderStyle::Ridge, _) | (_, BorderStyle::Ridge) => BorderCornerKind::Unhandled,
            (BorderStyle::Outset, _) | (_, BorderStyle::Outset) => BorderCornerKind::Unhandled,
            (BorderStyle::Inset, _) | (_, BorderStyle::Inset) => BorderCornerKind::Unhandled,
        }
    }

    fn get_edge(&self,
                edge: &BorderSide,
                width: f32) -> (BorderEdgeKind, f32) {
        if width == 0.0 {
            return (BorderEdgeKind::None, 0.0);
        }

        match edge.style {
            BorderStyle::None |
            BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),

            BorderStyle::Solid |
            BorderStyle::Inset |
            BorderStyle::Outset => (BorderEdgeKind::Solid, width),

            BorderStyle::Double |
            BorderStyle::Dotted |
            BorderStyle::Dashed |
            BorderStyle::Groove |
            BorderStyle::Ridge => (BorderEdgeKind::Unhandled, width),
        }
    }
}

impl FrameBuilder {
    fn add_normal_border_primitive(&mut self,
                                   rect: &LayerRect,
                                   border: &NormalBorder,
                                   widths: &BorderWidths,
                                   clip_id: ClipId,
                                   clip_region: &ClipRegion,
                                   use_new_border_path: bool) {
        let radius = &border.radius;
        let left = &border.left;
        let right = &border.right;
        let top = &border.top;
        let bottom = &border.bottom;

        // These colors are used during inset/outset scaling.
        let left_color      = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
        let top_color       = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
        let right_color     = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
        let bottom_color    = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);

        let prim_cpu = BorderPrimitiveCpu {
            use_new_border_path: use_new_border_path,
        };

        let prim_gpu = BorderPrimitiveGpu {
            colors: [ left_color, top_color, right_color, bottom_color ],
            widths: [ widths.left,
                      widths.top,
                      widths.right,
                      widths.bottom ],
            style: [
                pack_as_float(left.style as u32),
                pack_as_float(top.style as u32),
                pack_as_float(right.style as u32),
                pack_as_float(bottom.style as u32),
            ],
            radii: [
                radius.top_left,
                radius.top_right,
                radius.bottom_right,
                radius.bottom_left,
            ],
        };

        self.add_primitive(clip_id,
                           &rect,
                           clip_region,
                           &[],
                           PrimitiveContainer::Border(prim_cpu, prim_gpu));
    }

    // TODO(gw): This allows us to move border types over to the
    // simplified shader model one at a time. Once all borders
    // are converted, this can be removed, along with the complex
    // border code path.
    pub fn add_normal_border(&mut self,
                             rect: &LayerRect,
                             border: &NormalBorder,
                             widths: &BorderWidths,
                             clip_id: ClipId,
                             clip_region: &ClipRegion) {
        // The border shader is quite expensive. For simple borders, we can just draw
        // the border with a few rectangles. This generally gives better batching, and
        // a GPU win in fragment shader time.
        // More importantly, the software (OSMesa) implementation we run tests on is
        // particularly slow at running our complex border shader, compared to the
        // rectangle shader. This has the effect of making some of our tests time
        // out more often on CI (the actual cause is simply too many Servo processes and
        // threads being run on CI at once).

        let radius = &border.radius;
        let left = &border.left;
        let right = &border.right;
        let top = &border.top;
        let bottom = &border.bottom;

        let corners = [
            border.get_corner(left, widths.left, top, widths.top, &radius.top_left),
            border.get_corner(top, widths.top, right, widths.right, &radius.top_right),
            border.get_corner(right, widths.right, bottom, widths.bottom, &radius.bottom_right),
            border.get_corner(bottom, widths.bottom, left, widths.left, &radius.bottom_left),
        ];

        // If any of the corners are unhandled, fall back to slow path for now.
        if corners.iter().any(|c| *c == BorderCornerKind::Unhandled) {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             false);
            return;
        }

        let (left_edge, left_len) = border.get_edge(left, widths.left);
        let (top_edge, top_len) = border.get_edge(top, widths.top);
        let (right_edge, right_len) = border.get_edge(right, widths.right);
        let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom);

        let edges = [
            left_edge,
            top_edge,
            right_edge,
            bottom_edge,
        ];

        // If any of the edges are unhandled, fall back to slow path for now.
        if edges.iter().any(|e| *e == BorderEdgeKind::Unhandled) {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             false);
            return;
        }

        // Use a simple rectangle case when all edges and corners are either
        // solid or none.
        let all_corners_simple = corners.iter().all(|c| {
            *c == BorderCornerKind::Solid || *c == BorderCornerKind::None
        });
        let all_edges_simple = edges.iter().all(|e| {
            *e == BorderEdgeKind::Solid || *e == BorderEdgeKind::None
        });

        if all_corners_simple && all_edges_simple {
            let p0 = rect.origin;
            let p1 = rect.bottom_right();
            let rect_width = rect.size.width;
            let rect_height = rect.size.height;

            // Add a solid rectangle for each visible edge/corner combination.
            if top_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(p0,
                                                         LayerSize::new(rect_width, top_len)),
                                         clip_region,
                                         &border.top.color,
                                         PrimitiveFlags::None);
            }
            if left_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p0.x, p0.y + top_len),
                                                         LayerSize::new(left_len,
                                                                        rect_height - top_len - bottom_len)),
                                         clip_region,
                                         &border.left.color,
                                         PrimitiveFlags::None);
            }
            if right_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p1.x - right_len,
                                                                         p0.y + top_len),
                                                         LayerSize::new(right_len,
                                                                        rect_height - top_len - bottom_len)),
                                         clip_region,
                                         &border.right.color,
                                         PrimitiveFlags::None);
            }
            if bottom_edge == BorderEdgeKind::Solid {
                self.add_solid_rectangle(clip_id,
                                         &LayerRect::new(LayerPoint::new(p0.x, p1.y - bottom_len),
                                                         LayerSize::new(rect_width, bottom_len)),
                                         clip_region,
                                         &border.bottom.color,
                                         PrimitiveFlags::None);
            }
        } else {
            self.add_normal_border_primitive(rect,
                                             border,
                                             widths,
                                             clip_id,
                                             clip_region,
                                             true);
        }
    }
}

pub trait BorderSideHelpers {
    fn border_color(&self,
                    scale_factor_0: f32,
                    scale_factor_1: f32,
                    black_color_0: f32,
                    black_color_1: f32) -> ColorF;
}

impl BorderSideHelpers for BorderSide {
    fn border_color(&self,
                    scale_factor_0: f32,
                    scale_factor_1: f32,
                    black_color_0: f32,
                    black_color_1: f32) -> ColorF {
        match self.style {
            BorderStyle::Inset => {
                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
                    self.color.scale_rgb(scale_factor_1)
                } else {
                    ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
                }
            }
            BorderStyle::Outset => {
                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
                    self.color.scale_rgb(scale_factor_0)
                } else {
                    ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
                }
            }
            _ => self.color,
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::fmt::{self, Formatter, Debug};
use libc::{c_int};

pub struct Processus {
    pub name: String, // name of the program
    pub cmd: String, // command line
    pub exe: String, // path to the executable
    pub pid: i64, // pid of the processus
    pub environ: Vec<String>, // environment of the processus
    pub cwd: String, // current working directory
    pub root: String, // path of the root directory
    pub memory: u64, // memory usage
    utime: u64,
    stime: u64,
    pub cpu_usage: f32 // total cpu usage
}

impl Processus {
    pub fn new(pid: i64) -> Processus {
        Processus {
            name: String::new(),
            pid: pid,
            cmd: String::new(),
            environ: Vec::new(),
            exe: String::new(),
            cwd: String::new(),
            root: String::new(),
            memory: 0,
            cpu_usage: 0f32,
            utime: 0,
            stime: 0
        }
    }

    pub fn kill(&self, signal: ::Signal) -> bool {
        unsafe { ::ffi::kill(self.pid as c_int, signal as c_int) == 0 }
    }
}

impl Debug for Processus {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "pid: {}\n", self.pid);
        write!(f, "name: {}\n", self.name);
        write!(f, "environment:");
        for var in self.environ.iter() {
            write!(f, "\n\t{}", var);
        }
        write!(f, "command: {}\n", self.cmd);
        write!(f, "executable path: {}\n", self.exe);
        write!(f, "current working directory: {}\n", self.cwd);
        write!(f, "memory usage: {} kB\n", self.memory);
        write!(f, "cpu usage: {}%\n", self.cpu_usage);
        write!(f, "root path: {}", self.root)
    }
}

pub fn set_time(p: &mut Processus, utime: u64, stime: u64) {
    p.utime = utime;
    p.stime = stime;
}

pub fn compute_cpu_usage(p: &mut Processus, old_utime: u64, old_stime: u64, total_time: u64, old_total_time: u64) {
    p.cpu_usage = 100f32 * (p.utime - old_utime) as f32 / (total_time - old_total_time) as f32;
}

pub fn get_raw_processus_times(p: &Processus) -> (u64, u64) {
    (p.utime, p.stime)
}<commit_msg>Add clone trait to Processus struct<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::fmt::{self, Formatter, Debug};
use libc::{c_int};

#[derive(Clone)]
pub struct Processus {
    pub name: String, // name of the program
    pub cmd: String, // command line
    pub exe: String, // path to the executable
    pub pid: i64, // pid of the processus
    pub environ: Vec<String>, // environment of the processus
    pub cwd: String, // current working directory
    pub root: String, // path of the root directory
    pub memory: u64, // memory usage
    utime: u64,
    stime: u64,
    pub cpu_usage: f32 // total cpu usage
}

impl Processus {
    pub fn new(pid: i64) -> Processus {
        Processus {
            name: String::new(),
            pid: pid,
            cmd: String::new(),
            environ: Vec::new(),
            exe: String::new(),
            cwd: String::new(),
            root: String::new(),
            memory: 0,
            cpu_usage: 0f32,
            utime: 0,
            stime: 0
        }
    }

    pub fn kill(&self, signal: ::Signal) -> bool {
        unsafe { ::ffi::kill(self.pid as c_int, signal as c_int) == 0 }
    }
}

impl Debug for Processus {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "pid: {}\n", self.pid);
        write!(f, "name: {}\n", self.name);
        write!(f, "environment:");
        for var in self.environ.iter() {
            write!(f, "\n\t{}", var);
        }
        write!(f, "command: {}\n", self.cmd);
        write!(f, "executable path: {}\n", self.exe);
        write!(f, "current working directory: {}\n", self.cwd);
        write!(f, "memory usage: {} kB\n", self.memory);
        write!(f, "cpu usage: {}%\n", self.cpu_usage);
        write!(f, "root path: {}", self.root)
    }
}

pub fn set_time(p: &mut Processus, utime: u64, stime: u64) {
    p.utime = utime;
    p.stime = stime;
}

pub fn compute_cpu_usage(p: &mut Processus, old_utime: u64, old_stime: u64, total_time: u64, old_total_time: u64) {
    p.cpu_usage = 100f32 * (p.utime - old_utime) as f32 / (total_time - old_total_time) as f32;
}

pub fn get_raw_processus_times(p: &Processus) -> (u64, u64) {
    (p.utime, p.stime)
}<|endoftext|>


<commit_before>use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{Result, Mode, Level, Trigger, PullUpDown::{self, *}, mem::GpioMem, interrupt::{AsyncInterrupt, EventLoop}};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(pin: u8, event_loop: Arc<Mutex<EventLoop>>, gpio_mem: Arc<GpioMem>, gpio_cdev: Arc<File>) -> Pin {
        Pin { pin, event_loop, gpio_mem, gpio_cdev }
    }

    /// Mutably borrows the pin as an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn as_input(&mut self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `as_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn as_input_pullup(&mut self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `as_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn as_input_pulldown(&mut self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Mutably borrows the pin as an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn as_output(&mut self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Mutably borrows the pin as an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn as_alt(&mut self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    #[inline]
    pub(crate) fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl<'a> $struct<'a> {
            /// Returns the value of `clear_on_drop`.
            pub fn clear_on_drop(&self) -> bool {
                self.clear_on_drop
            }

            /// When enabled, resets pin's mode to its original state when it goes out of scope.
            /// By default, this is set to `true`.
            ///
            /// # Note
            ///
            /// Drop methods aren't called when a program is abnormally terminated, for
            /// instance when a user presses Ctrl + C, and the `SIGINT` signal
            /// isn't caught. You catch those using crates such as [`simple_signal`].
            ///
            /// [`simple_signal`]: https://crates.io/crates/simple-signal
            /// [`cleanup`]: #method.cleanup
            pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
                self.clear_on_drop = clear_on_drop;
            }
        }

        impl<'a> Drop for $struct<'a> {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if self.clear_on_drop == false {
                    return
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }

    }
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin<'a> {
    pub(crate) pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl<'a> InputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, pud_mode: PullUpDown) -> InputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin { pin, prev_mode, async_interrupt: None, clear_on_drop: true }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set too `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(&mut self, reset: bool, timeout: Option<Duration>) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin<'a> {
    pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> OutputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin) -> OutputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin { pin, prev_mode, clear_on_drop: true }
    }

    impl_output!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin<'a> {
    pin: &'a mut Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> AltPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, mode: Mode) -> AltPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin { pin, mode, prev_mode, clear_on_drop: true }
    }

    impl_input!();
    impl_output!();
}
impl_drop!(AltPin);
<commit_msg>Add `read` to `OutputPin`.<commit_after>use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{Result, Mode, Level, Trigger, PullUpDown::{self, *}, mem::GpioMem, interrupt::{AsyncInterrupt, EventLoop}};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(pin: u8, event_loop: Arc<Mutex<EventLoop>>, gpio_mem: Arc<GpioMem>, gpio_cdev: Arc<File>) -> Pin {
        Pin { pin, event_loop, gpio_mem, gpio_cdev }
    }

    /// Mutably borrows the pin as an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn as_input(&mut self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `as_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn as_input_pullup(&mut self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `as_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn as_input_pulldown(&mut self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Mutably borrows the pin as an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn as_output(&mut self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Mutably borrows the pin as an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn as_alt(&mut self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    #[inline]
    pub(crate) fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl<'a> $struct<'a> {
            /// Returns the value of `clear_on_drop`.
            pub fn clear_on_drop(&self) -> bool {
                self.clear_on_drop
            }

            /// When enabled, resets pin's mode to its original state when it goes out of scope.
            /// By default, this is set to `true`.
            ///
            /// # Note
            ///
            /// Drop methods aren't called when a program is abnormally terminated, for
            /// instance when a user presses Ctrl + C, and the `SIGINT` signal
            /// isn't caught. You catch those using crates such as [`simple_signal`].
            ///
            /// [`simple_signal`]: https://crates.io/crates/simple-signal
            /// [`cleanup`]: #method.cleanup
            pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
                self.clear_on_drop = clear_on_drop;
            }
        }

        impl<'a> Drop for $struct<'a> {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if self.clear_on_drop == false {
                    return
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }

    }
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin<'a> {
    pub(crate) pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl<'a> InputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, pud_mode: PullUpDown) -> InputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin { pin, prev_mode, async_interrupt: None, clear_on_drop: true }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set too `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(&mut self, reset: bool, timeout: Option<Duration>) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin<'a> {
    pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> OutputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin) -> OutputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin { pin, prev_mode, clear_on_drop: true }
    }

    impl_input!();
    impl_output!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin<'a> {
    pin: &'a mut Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> AltPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, mode: Mode) -> AltPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin { pin, mode, prev_mode, clear_on_drop: true }
    }

    impl_input!();
    impl_output!();
}
impl_drop!(AltPin);
<|endoftext|>


<commit_before>#[cfg(feature="bigdecimal")]
mod bigdecimal {
    extern crate num_traits;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate bigdecimal;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{Sign, BigInt, BigUint};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, Zero, ToPrimitive};
    use std::error::Error;
    use std::io::prelude::*;

    use pg::Pg;
    use pg::data_types::PgNumeric;
    use types::{self, FromSql, ToSql, ToSqlOutput, IsNull};

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();
            let scale = scale as u16;
            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale as u16 / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits[index_of_decimal..]
                .iter()
                .rev()
                .take_while(|i| i.is_zero())
                .count()
            }
            else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits, scale, weight
                },
                Sign::Minus => PgNumeric::Negative {
                    digits, scale, weight
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<types::Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut ToSqlOutput<W, Pg>) -> Result<IsNull, Box<Error + Send + Sync>> {
            let numeric = PgNumeric::from(self);
            ToSql::<types::Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<types::Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> Result<Self, Box<Error+Send+Sync>> {
            let (sign, weight, _, digits) = match PgNumeric::from_sql(numeric)? {
                PgNumeric::Positive { weight, scale, digits } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative { weight, scale, digits } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
            };
            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result = result * BigUint::from(10_000u64);
                result = result + BigUint::from(digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * ( (weight as i64) - count + 1);
            // FIXME: `scale` allows to drop some insignificant figures, which is currently unimplemented.
            // This means that e.g. PostgreSQL 0.01 will be interpreted as 0.0100
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp);
            Ok(result)
        }
    }

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

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![10] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive { weight: 1, scale: 0, digits: vec![1, 0] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive { weight: 1, scale: 0, digits: vec![1, 1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive { weight: 2, scale: 0, digits: vec![1, 0, 0] };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1, 1000] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 2, digits: vec![1, 1000] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive { weight: -1, scale: 1, digits: vec![1000] };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }
    }
}
<commit_msg>Implement review feedback from #1096<commit_after>#[cfg(feature="bigdecimal")]
mod bigdecimal {
    extern crate num_traits;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate bigdecimal;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{Sign, BigInt, BigUint};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, Zero, ToPrimitive};
    use std::error::Error;
    use std::io::prelude::*;

    use pg::Pg;
    use pg::data_types::PgNumeric;
    use types::{self, FromSql, ToSql, ToSqlOutput, IsNull};

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();
            let scale = scale as u16;
            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale as u16 / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits.get(index_of_decimal..).expect("enough digits exist")
                    .iter()
                    .rev()
                    .take_while(|i| i.is_zero())
                    .count()
            }
            else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits, scale, weight
                },
                Sign::Minus => PgNumeric::Negative {
                    digits, scale, weight
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<types::Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut ToSqlOutput<W, Pg>) -> Result<IsNull, Box<Error + Send + Sync>> {
            let numeric = PgNumeric::from(self);
            ToSql::<types::Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<types::Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> Result<Self, Box<Error+Send+Sync>> {
            let (sign, weight, _, digits) = match PgNumeric::from_sql(numeric)? {
                PgNumeric::Positive { weight, scale, digits } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative { weight, scale, digits } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
            };
            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result = result * BigUint::from(10_000u64);
                result = result + BigUint::from(digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * ( (weight as i64) - count + 1);
            // FIXME: `scale` allows to drop some insignificant figures, which is currently unimplemented.
            // This means that e.g. PostgreSQL 0.01 will be interpreted as 0.0100
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp);
            Ok(result)
        }
    }

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

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![10] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive { weight: 1, scale: 0, digits: vec![1, 0] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive { weight: 1, scale: 0, digits: vec![1, 1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive { weight: 2, scale: 0, digits: vec![1, 0, 0] };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 0, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 1, digits: vec![1, 1000] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive { weight: 0, scale: 2, digits: vec![1, 1000] };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive { weight: -1, scale: 1, digits: vec![1000] };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }
    }
}
<|endoftext|>


<commit_before>//! Draw rectangle
//!
//! This module contains the definintion of a rectangle with possibly rounded
//! corners. It contains the code to draw the rectangle and defines properties
//! like color and shape. The rectangle dimensions and location are specified by
//! `types::Rectangle`.
//!
//! To draw a square with side 10 and top left corner in (0, 0), do the
//! following:
//! ```ignore
//! let rectangle = Rectangle::new(color::BLACK);
//! let dims = square(0.0, 0.0, 10.0);
//! rectangle.draw(dims, &draw_state::Default::default(), transform, g);
//! ```

pub use crate::math::margin_rectangle as margin;
use crate::{
    math::{Matrix2d, Scalar},
    triangulation, types,
    types::{Color, Radius, Resolution},
    DrawState, Graphics,
};

/// Create `types::Rectangle` by the two opposite corners.
///
/// The corners are in (x0, y0) and (x1, y1).
pub fn rectangle_by_corners(x0: Scalar, y0: Scalar, x1: Scalar, y1: Scalar) -> types::Rectangle {
    let (xmin, w) = if x0 <= x1 {
        (x0, x1 - x0)
    } else {
        (x1, x0 - x1)
    };

    let (ymin, h) = if y0 <= y1 {
        (y0, y1 - y0)
    } else {
        (y1, y0 - y1)
    };

    [xmin, ymin, w, h]
}

/// Use x, y, half-width, half-height
pub fn centered(rect: types::Rectangle) -> types::Rectangle {
    [
        rect[0] - rect[2],
        rect[1] - rect[3],
        2.0 * rect[2],
        2.0 * rect[3],
    ]
}

/// Create `types::Rectangle` for a square with a center in (`x`, `y`) and side
/// `2 * radius`.
pub fn centered_square(x: Scalar, y: Scalar, radius: Scalar) -> types::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Create `types::Rectangle` for a square with a top-left corner in (`x`, `y`)
/// and side `size`.
pub fn square(x: Scalar, y: Scalar, size: Scalar) -> types::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle corners
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners, with resolution per corner.
    Round(Radius, Resolution),
    /// Bevel corners
    Bevel(Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: Color,
    /// The radius of the border. The half-width of the line by which border is
    /// drawn.
    pub radius: Radius,
}

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: Color) -> Rectangle {
        Rectangle {
            color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle with rounded corners.
    pub fn new_round(color: Color, round_radius: Radius) -> Rectangle {
        Rectangle {
            color,
            shape: Shape::Round(round_radius, 32),
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn new_border(color: Color, radius: Radius) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border { color, radius }),
        }
    }

    /// Creates a new rectangle border with rounded corners.
    pub fn new_round_border(
        color: Color,
        round_radius: Radius,
        border_radius: Radius,
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius, 32),
            border: Some(Border {
                color,
                radius: border_radius,
            }),
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets shape of the corners.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Sets border properties.
    pub fn border(mut self, value: Border) -> Self {
        self.border = Some(value);
        self
    }

    /// Sets optional border.
    pub fn maybe_border(mut self, value: Option<Border>) -> Self {
        self.border = value;
        self
    }

    /// Draws the rectangle by corners using the default method.
    #[inline(always)]
    pub fn draw_from_to<P: Into<types::Vec2d>, G>(
        &self,
        from: P,
        to: P,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        let from = from.into();
        let to = to.into();
        g.rectangle(
            self,
            rectangle_by_corners(from[0], from[1], to[0], to[1]),
            draw_state,
            transform,
        );
    }

    /// Draws the rectangle using the default method.
    ///
    /// `rectangle` defines the rectangle's location and dimensions,
    /// `draw_state` draw state, `draw_state::Default::default()` can be used
    /// as a default, `transform` is the transformation matrix, `g` is the
    /// `Graphics` implementation, that is used to actually draw the rectangle.s
    #[inline(always)]
    pub fn draw<R: Into<types::Rectangle>, G>(
        &self,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        g.rectangle(self, rectangle, draw_state, transform);
    }

    /// Draws the rectangle using triangulation.
    ///
    /// This is the default implementation of draw() that will be used if `G`
    /// does not redefine `Graphics::rectangle()`.
    pub fn draw_tri<R: Into<types::Rectangle>, G>(
        &self,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        let rectangle = rectangle.into();
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &self.color, |f| {
                        f(&triangulation::rect_tri_list_xy(transform, rectangle))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(
                            resolution,
                            transform,
                            rectangle,
                            round_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(
                            2,
                            transform,
                            rectangle,
                            bevel_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
            }
        }

        if let Some(Border {
            color,
            radius: border_radius,
        }) = self.border
        {
            if color[3] == 0.0 {
                return;
            }
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &color, |f| {
                        f(&triangulation::rect_border_tri_list_xy(
                            transform,
                            rectangle,
                            border_radius,
                        ))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(
                            resolution,
                            transform,
                            rectangle,
                            round_radius,
                            border_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(
                            2,
                            transform,
                            rectangle,
                            bevel_radius,
                            border_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
            }
        }
    }
}

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

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .color([0.0; 4])
            .shape(Shape::Round(10.0, 32))
            .border(Border {
                color: [0.0; 4],
                radius: 4.0,
            });
    }

    #[test]
    fn test_rectangle_by_corners() {
        assert_eq!(
            rectangle_by_corners(1.0, -1.0, 2.0, 3.0),
            [1.0, -1.0, 1.0, 4.0]
        );
        assert_eq!(
            rectangle_by_corners(2.0, 3.0, 1.0, -1.0),
            [1.0, -1.0, 1.0, 4.0]
        );
    }
}
<commit_msg>Update documentation of rectangle::centered<commit_after>//! Draw rectangle
//!
//! This module contains the definintion of a rectangle with possibly rounded
//! corners. It contains the code to draw the rectangle and defines properties
//! like color and shape. The rectangle dimensions and location are specified by
//! `types::Rectangle`.
//!
//! To draw a square with side 10 and top left corner in (0, 0), do the
//! following:
//! ```ignore
//! let rectangle = Rectangle::new(color::BLACK);
//! let dims = square(0.0, 0.0, 10.0);
//! rectangle.draw(dims, &draw_state::Default::default(), transform, g);
//! ```

pub use crate::math::margin_rectangle as margin;
use crate::{
    math::{Matrix2d, Scalar},
    triangulation, types,
    types::{Color, Radius, Resolution},
    DrawState, Graphics,
};

/// Create `types::Rectangle` by the two opposite corners.
///
/// The corners are in (x0, y0) and (x1, y1).
pub fn rectangle_by_corners(x0: Scalar, y0: Scalar, x1: Scalar, y1: Scalar) -> types::Rectangle {
    let (xmin, w) = if x0 <= x1 {
        (x0, x1 - x0)
    } else {
        (x1, x0 - x1)
    };

    let (ymin, h) = if y0 <= y1 {
        (y0, y1 - y0)
    } else {
        (y1, y0 - y1)
    };

    [xmin, ymin, w, h]
}

/// Create a centered rectangle.
///
/// `rect` is interpreted as `[x, y, half_width, half_height]`
///
/// Note that passing an existing `types::Rectangle` in here will not produce a rectangle of the
/// same
/// dimensions
///
/// # Example
/// ```
/// use graphics::rectangle::centered;
///
/// // We create a rectangle centered on [0.0, 0.0] with width 2.0 and height 6.0
/// let centered_rect = centered([0.0, 0.0, 1.0, 3.0]);
/// assert_eq!(centered_rect, [-1.0, -3.0, 2.0, 6.0]);
/// ```
pub fn centered(rect: types::Rectangle) -> types::Rectangle {
    [
        rect[0] - rect[2],
        rect[1] - rect[3],
        2.0 * rect[2],
        2.0 * rect[3],
    ]
}

/// Create `types::Rectangle` for a square with a center in (`x`, `y`) and side
/// `2 * radius`.
pub fn centered_square(x: Scalar, y: Scalar, radius: Scalar) -> types::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Create `types::Rectangle` for a square with a top-left corner in (`x`, `y`)
/// and side `size`.
pub fn square(x: Scalar, y: Scalar, size: Scalar) -> types::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle corners
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners, with resolution per corner.
    Round(Radius, Resolution),
    /// Bevel corners
    Bevel(Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: Color,
    /// The radius of the border. The half-width of the line by which border is
    /// drawn.
    pub radius: Radius,
}

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: Color) -> Rectangle {
        Rectangle {
            color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new rectangle with rounded corners.
    pub fn new_round(color: Color, round_radius: Radius) -> Rectangle {
        Rectangle {
            color,
            shape: Shape::Round(round_radius, 32),
            border: None,
        }
    }

    /// Creates a new rectangle border.
    pub fn new_border(color: Color, radius: Radius) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border { color, radius }),
        }
    }

    /// Creates a new rectangle border with rounded corners.
    pub fn new_round_border(
        color: Color,
        round_radius: Radius,
        border_radius: Radius,
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius, 32),
            border: Some(Border {
                color,
                radius: border_radius,
            }),
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets shape of the corners.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Sets border properties.
    pub fn border(mut self, value: Border) -> Self {
        self.border = Some(value);
        self
    }

    /// Sets optional border.
    pub fn maybe_border(mut self, value: Option<Border>) -> Self {
        self.border = value;
        self
    }

    /// Draws the rectangle by corners using the default method.
    #[inline(always)]
    pub fn draw_from_to<P: Into<types::Vec2d>, G>(
        &self,
        from: P,
        to: P,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        let from = from.into();
        let to = to.into();
        g.rectangle(
            self,
            rectangle_by_corners(from[0], from[1], to[0], to[1]),
            draw_state,
            transform,
        );
    }

    /// Draws the rectangle using the default method.
    ///
    /// `rectangle` defines the rectangle's location and dimensions,
    /// `draw_state` draw state, `draw_state::Default::default()` can be used
    /// as a default, `transform` is the transformation matrix, `g` is the
    /// `Graphics` implementation, that is used to actually draw the rectangle.s
    #[inline(always)]
    pub fn draw<R: Into<types::Rectangle>, G>(
        &self,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        g.rectangle(self, rectangle, draw_state, transform);
    }

    /// Draws the rectangle using triangulation.
    ///
    /// This is the default implementation of draw() that will be used if `G`
    /// does not redefine `Graphics::rectangle()`.
    pub fn draw_tri<R: Into<types::Rectangle>, G>(
        &self,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G,
    ) where
        G: Graphics,
    {
        let rectangle = rectangle.into();
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &self.color, |f| {
                        f(&triangulation::rect_tri_list_xy(transform, rectangle))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(
                            resolution,
                            transform,
                            rectangle,
                            round_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &self.color, |f| {
                        triangulation::with_round_rectangle_tri_list(
                            2,
                            transform,
                            rectangle,
                            bevel_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
            }
        }

        if let Some(Border {
            color,
            radius: border_radius,
        }) = self.border
        {
            if color[3] == 0.0 {
                return;
            }
            match self.shape {
                Shape::Square => {
                    g.tri_list(draw_state, &color, |f| {
                        f(&triangulation::rect_border_tri_list_xy(
                            transform,
                            rectangle,
                            border_radius,
                        ))
                    });
                }
                Shape::Round(round_radius, resolution) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(
                            resolution,
                            transform,
                            rectangle,
                            round_radius,
                            border_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(draw_state, &color, |f| {
                        triangulation::with_round_rectangle_border_tri_list(
                            2,
                            transform,
                            rectangle,
                            bevel_radius,
                            border_radius,
                            |vertices| f(vertices),
                        )
                    });
                }
            }
        }
    }
}

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

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .color([0.0; 4])
            .shape(Shape::Round(10.0, 32))
            .border(Border {
                color: [0.0; 4],
                radius: 4.0,
            });
    }

    #[test]
    fn test_rectangle_by_corners() {
        assert_eq!(
            rectangle_by_corners(1.0, -1.0, 2.0, 3.0),
            [1.0, -1.0, 1.0, 4.0]
        );
        assert_eq!(
            rectangle_by_corners(2.0, 3.0, 1.0, -1.0),
            [1.0, -1.0, 1.0, 4.0]
        );
    }
}
<|endoftext|>


<commit_before>
use color::Color;
use dimensions::Dimensions;
use graphics;
use graphics::{
    Graphics,
    Context,
};
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use point::Point;
use ui_context::UiContext;
use utils::map_range;

/// Represents the state of the Button widget.
#[derive(PartialEq, Debug, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

/// Draw a basic rectangle. The primary purpose
/// of this is to be used as a building block for
/// other widgets.
pub fn draw<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    state: State,
    pos: Point,
    dim: Dimensions,
    maybe_frame: Option<(f64, Color)>,
    color: Color
) {
    let context = &Context::abs(win_w, win_h);
    if let Some((_, f_color)) = maybe_frame {
        draw_frame(context, graphics, pos, dim, f_color)
    }
    let f_width = if let Some((f_width, _)) = maybe_frame { f_width } else { 0.0 };
    draw_normal(context, graphics, state, pos, dim, f_width, color);
}

/// Draw the button border.
fn draw_frame<B: Graphics>(
    context: &Context,
    graphics: &mut B,
    pos: Point,
    dim: Dimensions,
    color: Color
) {
    let Color(col) = color;
    graphics::Rectangle::new(col)
        .draw(
            [pos[0], pos[1], dim[0], dim[1]],
            &context.draw_state,
            context.transform,
            graphics
        );
}

/// Draw the rectangle while considering frame
/// width for position and dimensions.
fn draw_normal<B: Graphics>(
    context: &Context,
    graphics: &mut B,
    state: State,
    pos: Point,
    dim: Dimensions,
    frame_width: f64,
    color: Color
) {
    let Color(col) = match state {
        State::Normal => color,
        State::Highlighted => color.highlighted(),
        State::Clicked => color.clicked(),
    };
    graphics::Rectangle::new(col)
        .draw([pos[0] + frame_width,
            pos[1] + frame_width,
            dim[0] - frame_width * 2.0,
            dim[1] - frame_width * 2.0],
        &context.draw_state,
        context.transform,
        graphics);
}

/// Return whether or not the widget has been hit by a mouse_press.
#[inline]
pub fn is_over(pos: Point,
               mouse_pos: Point,
               dim: Dimensions) -> bool {
    if mouse_pos[0] > pos[0]
    && mouse_pos[1] > pos[1]
    && mouse_pos[0] < pos[0] + dim[0]
    && mouse_pos[1] < pos[1] + dim[1] { true }
    else { false }
}

/// Draw a label centered within a rect of given position and dimensions.
pub fn draw_with_centered_label<B, C>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    uic: &mut UiContext<C>,
    state: State,
    pos: Point,
    dim: Dimensions,
    maybe_frame: Option<(f64, Color)>,
    color: Color,
    text: &str,
    font_size: FontSize,
    text_color: Color
)
    where
        B: Graphics<Texture = <C as CharacterCache>::Texture>,
        C: CharacterCache
{
    let context = &Context::abs(win_w, win_h);
    if let Some((_, f_color)) = maybe_frame {
        draw_frame(context, graphics, pos, dim, f_color)
    }
    let f_width = if let Some((f_width, _)) = maybe_frame { f_width } else { 0.0 };
    draw_normal(context, graphics, state, pos, dim, f_width, color);
    let text_w = label::width(uic, font_size, text);
    let l_pos = [pos[0] + (dim[0] - text_w) / 2.0, pos[1] + (dim[1] - font_size as f64) / 2.0];
    uic.draw_text(graphics, l_pos, font_size, text_color, text);
}

#[derive(Copy)]
pub enum Corner {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
}

/// Return which corner of the rectangle the given Point is within.
pub fn corner(rect_p: Point, p: Point, dim: Dimensions) -> Corner {
    let x_temp = p[0] - rect_p[0];
    let y_temp = p[1] - rect_p[1];
    let x_perc = map_range(x_temp, 0.0, dim[0], 0f64, 1.0);
    let y_perc = map_range(y_temp, dim[1], 0.0, 0f64, 1.0);
    if      x_perc <= 0.5 && y_perc <= 0.5 { Corner::BottomLeft }
    else if x_perc >  0.5 && y_perc <= 0.5 { Corner::BottomRight }
    else if x_perc <= 0.5 && y_perc >  0.5 { Corner::TopLeft }
    else                                   { Corner::TopRight }
}
<commit_msg>Removed `Context` from rectangle.rs<commit_after>
use color::Color;
use dimensions::Dimensions;
use graphics;
use graphics::{ DrawState, Graphics };
use graphics::vecmath::Matrix2d;
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use point::Point;
use ui_context::UiContext;
use utils::map_range;

/// Represents the state of the Button widget.
#[derive(PartialEq, Debug, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

/// Draw a basic rectangle. The primary purpose
/// of this is to be used as a building block for
/// other widgets.
pub fn draw<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    state: State,
    pos: Point,
    dim: Dimensions,
    maybe_frame: Option<(f64, Color)>,
    color: Color
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    if let Some((_, f_color)) = maybe_frame {
        draw_frame(&draw_state, transform, graphics, pos, dim, f_color)
    }
    let f_width = if let Some((f_width, _)) = maybe_frame { f_width } else { 0.0 };
    draw_normal(&draw_state, transform, graphics, state, pos, dim, f_width, color);
}

/// Draw the button border.
fn draw_frame<B: Graphics>(
    draw_state: &DrawState,
    transform: Matrix2d,
    graphics: &mut B,
    pos: Point,
    dim: Dimensions,
    color: Color
) {
    graphics::Rectangle::new(color.0)
        .draw(
            [pos[0], pos[1], dim[0], dim[1]],
            draw_state,
            transform,
            graphics
        );
}

/// Draw the rectangle while considering frame
/// width for position and dimensions.
fn draw_normal<B: Graphics>(
    draw_state: &DrawState,
    transform: Matrix2d,
    graphics: &mut B,
    state: State,
    pos: Point,
    dim: Dimensions,
    frame_width: f64,
    color: Color
) {
    let Color(col) = match state {
        State::Normal => color,
        State::Highlighted => color.highlighted(),
        State::Clicked => color.clicked(),
    };
    graphics::Rectangle::new(col)
        .draw([pos[0] + frame_width,
            pos[1] + frame_width,
            dim[0] - frame_width * 2.0,
            dim[1] - frame_width * 2.0],
        draw_state,
        transform,
        graphics);
}

/// Return whether or not the widget has been hit by a mouse_press.
#[inline]
pub fn is_over(pos: Point,
               mouse_pos: Point,
               dim: Dimensions) -> bool {
    if mouse_pos[0] > pos[0]
    && mouse_pos[1] > pos[1]
    && mouse_pos[0] < pos[0] + dim[0]
    && mouse_pos[1] < pos[1] + dim[1] { true }
    else { false }
}

/// Draw a label centered within a rect of given position and dimensions.
pub fn draw_with_centered_label<B, C>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    uic: &mut UiContext<C>,
    state: State,
    pos: Point,
    dim: Dimensions,
    maybe_frame: Option<(f64, Color)>,
    color: Color,
    text: &str,
    font_size: FontSize,
    text_color: Color
)
    where
        B: Graphics<Texture = <C as CharacterCache>::Texture>,
        C: CharacterCache
{
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    if let Some((_, f_color)) = maybe_frame {
        draw_frame(&draw_state, transform, graphics, pos, dim, f_color)
    }
    let f_width = if let Some((f_width, _)) = maybe_frame { f_width } else { 0.0 };
    draw_normal(&draw_state, transform, graphics, state, pos, dim, f_width, color);
    let text_w = label::width(uic, font_size, text);
    let l_pos = [pos[0] + (dim[0] - text_w) / 2.0, pos[1] + (dim[1] - font_size as f64) / 2.0];
    uic.draw_text(graphics, l_pos, font_size, text_color, text);
}

#[derive(Copy)]
pub enum Corner {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
}

/// Return which corner of the rectangle the given Point is within.
pub fn corner(rect_p: Point, p: Point, dim: Dimensions) -> Corner {
    let x_temp = p[0] - rect_p[0];
    let y_temp = p[1] - rect_p[1];
    let x_perc = map_range(x_temp, 0.0, dim[0], 0f64, 1.0);
    let y_perc = map_range(y_temp, dim[1], 0.0, 0f64, 1.0);
    if      x_perc <= 0.5 && y_perc <= 0.5 { Corner::BottomLeft }
    else if x_perc >  0.5 && y_perc <= 0.5 { Corner::BottomRight }
    else if x_perc <= 0.5 && y_perc >  0.5 { Corner::TopLeft }
    else                                   { Corner::TopRight }
}
<|endoftext|>