diff options
Diffstat (limited to 'vendor/criterion-plot/src')
-rwxr-xr-x | vendor/criterion-plot/src/axis.rs | 201 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/candlestick.rs | 154 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/curve.rs | 273 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/data.rs | 174 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/display.rs | 139 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/errorbar.rs | 293 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/filledcurve.rs | 143 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/grid.rs | 46 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/key.rs | 221 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/lib.rs | 1093 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/map.rs | 168 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/prelude.rs | 13 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/proxy.rs | 47 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/traits.rs | 35 |
14 files changed, 3000 insertions, 0 deletions
diff --git a/vendor/criterion-plot/src/axis.rs b/vendor/criterion-plot/src/axis.rs new file mode 100755 index 000000000..142c7fbda --- /dev/null +++ b/vendor/criterion-plot/src/axis.rs @@ -0,0 +1,201 @@ +//! Coordinate axis + +use std::borrow::Cow; +use std::iter::IntoIterator; + +use crate::map; +use crate::traits::{Configure, Data, Set}; +use crate::{ + grid, Axis, Default, Display, Grid, Label, Range, Scale, ScaleFactor, Script, TicLabels, +}; + +/// Properties of the coordinate axes +#[derive(Clone)] +pub struct Properties { + grids: map::grid::Map<grid::Properties>, + hidden: bool, + label: Option<Cow<'static, str>>, + logarithmic: bool, + range: Option<(f64, f64)>, + scale_factor: f64, + tics: Option<String>, +} + +impl Default for Properties { + fn default() -> Properties { + Properties { + grids: map::grid::Map::new(), + hidden: false, + label: None, + logarithmic: false, + range: None, + scale_factor: 1., + tics: None, + } + } +} + +impl Properties { + /// Hides the axis + /// + /// **Note** The `TopX` and `RightY` axes are hidden by default + pub fn hide(&mut self) -> &mut Properties { + self.hidden = true; + self + } + + /// Makes the axis visible + /// + /// **Note** The `BottomX` and `LeftY` axes are visible by default + pub fn show(&mut self) -> &mut Properties { + self.hidden = false; + self + } +} + +impl Configure<Grid> for Properties { + type Properties = grid::Properties; + + /// Configures the gridlines + fn configure<F>(&mut self, grid: Grid, configure: F) -> &mut Properties + where + F: FnOnce(&mut grid::Properties) -> &mut grid::Properties, + { + if self.grids.contains_key(grid) { + configure(self.grids.get_mut(grid).unwrap()); + } else { + let mut properties = Default::default(); + configure(&mut properties); + self.grids.insert(grid, properties); + } + + self + } +} + +impl Set<Label> for Properties { + /// Attaches a label to the axis + fn set(&mut self, label: Label) -> &mut Properties { + self.label = Some(label.0); + self + } +} + +impl Set<Range> for Properties { + /// Changes the range of the axis that will be shown + /// + /// **Note** All axes are auto-scaled by default + fn set(&mut self, range: Range) -> &mut Properties { + self.hidden = false; + + match range { + Range::Auto => self.range = None, + Range::Limits(low, high) => self.range = Some((low, high)), + } + + self + } +} + +impl Set<Scale> for Properties { + /// Sets the scale of the axis + /// + /// **Note** All axes use a linear scale by default + fn set(&mut self, scale: Scale) -> &mut Properties { + self.hidden = false; + + match scale { + Scale::Linear => self.logarithmic = false, + Scale::Logarithmic => self.logarithmic = true, + } + + self + } +} + +impl Set<ScaleFactor> for Properties { + /// Changes the *scale factor* of the axis. + /// + /// All the data plotted against this axis will have its corresponding coordinate scaled with + /// this factor before being plotted. + /// + /// **Note** The default scale factor is `1`. + fn set(&mut self, factor: ScaleFactor) -> &mut Properties { + self.scale_factor = factor.0; + + self + } +} + +impl<P, L> Set<TicLabels<P, L>> for Properties +where + L: IntoIterator, + L::Item: AsRef<str>, + P: IntoIterator, + P::Item: Data, +{ + /// Attaches labels to the tics of an axis + fn set(&mut self, tics: TicLabels<P, L>) -> &mut Properties { + let TicLabels { positions, labels } = tics; + + let pairs = positions + .into_iter() + .zip(labels.into_iter()) + .map(|(pos, label)| format!("'{}' {}", label.as_ref(), pos.f64())) + .collect::<Vec<_>>(); + + if pairs.is_empty() { + self.tics = None + } else { + self.tics = Some(pairs.join(", ")); + } + + self + } +} + +impl<'a> Script for (Axis, &'a Properties) { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let &(axis, properties) = self; + let axis_ = axis.display(); + + let mut script = if properties.hidden { + return format!("unset {}tics\n", axis_); + } else { + format!("set {}tics nomirror ", axis_) + }; + + if let Some(ref tics) = properties.tics { + script.push_str(&format!("({})", tics)) + } + + script.push('\n'); + + if let Some(ref label) = properties.label { + script.push_str(&format!("set {}label '{}'\n", axis_, label)) + } + + if let Some((low, high)) = properties.range { + script.push_str(&format!("set {}range [{}:{}]\n", axis_, low, high)) + } + + if properties.logarithmic { + script.push_str(&format!("set logscale {}\n", axis_)); + } + + for (grid, properties) in properties.grids.iter() { + script.push_str(&(axis, grid, properties).script()); + } + + script + } +} + +impl crate::ScaleFactorTrait for Properties { + fn scale_factor(&self) -> f64 { + self.scale_factor + } +} diff --git a/vendor/criterion-plot/src/candlestick.rs b/vendor/criterion-plot/src/candlestick.rs new file mode 100755 index 000000000..d1754e8c5 --- /dev/null +++ b/vendor/criterion-plot/src/candlestick.rs @@ -0,0 +1,154 @@ +//! "Candlestick" plots + +use std::borrow::Cow; +use std::iter::IntoIterator; + +use crate::data::Matrix; +use crate::traits::{self, Data, Set}; +use crate::{Color, Default, Display, Figure, Label, LineType, LineWidth, Plot, Script}; + +/// Properties common to candlestick plots +pub struct Properties { + color: Option<Color>, + label: Option<Cow<'static, str>>, + line_type: LineType, + linewidth: Option<f64>, +} + +impl Default for Properties { + fn default() -> Properties { + Properties { + color: None, + label: None, + line_type: LineType::Solid, + linewidth: None, + } + } +} + +impl Script for Properties { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let mut script = String::from("with candlesticks "); + + script.push_str(&format!("lt {} ", self.line_type.display())); + + if let Some(lw) = self.linewidth { + script.push_str(&format!("lw {} ", lw)) + } + + if let Some(color) = self.color { + script.push_str(&format!("lc rgb '{}' ", color.display())); + } + + if let Some(ref label) = self.label { + script.push_str("title '"); + script.push_str(label); + script.push('\'') + } else { + script.push_str("notitle") + } + + script + } +} + +impl Set<Color> for Properties { + /// Sets the line color + fn set(&mut self, color: Color) -> &mut Properties { + self.color = Some(color); + self + } +} + +impl Set<Label> for Properties { + /// Sets the legend label + fn set(&mut self, label: Label) -> &mut Properties { + self.label = Some(label.0); + self + } +} + +impl Set<LineType> for Properties { + /// Changes the line type + /// + /// **Note** By default `Solid` lines are used + fn set(&mut self, lt: LineType) -> &mut Properties { + self.line_type = lt; + self + } +} + +impl Set<LineWidth> for Properties { + /// Changes the width of the line + /// + /// # Panics + /// + /// Panics if `width` is a non-positive value + fn set(&mut self, lw: LineWidth) -> &mut Properties { + let lw = lw.0; + + assert!(lw > 0.); + + self.linewidth = Some(lw); + self + } +} + +/// A candlestick consists of a box and two whiskers that extend beyond the box +pub struct Candlesticks<X, WM, BM, BH, WH> { + /// X coordinate of the candlestick + pub x: X, + /// Y coordinate of the end point of the bottom whisker + pub whisker_min: WM, + /// Y coordinate of the bottom of the box + pub box_min: BM, + /// Y coordinate of the top of the box + pub box_high: BH, + /// Y coordinate of the end point of the top whisker + pub whisker_high: WH, +} + +impl<X, WM, BM, BH, WH> traits::Plot<Candlesticks<X, WM, BM, BH, WH>> for Figure +where + BH: IntoIterator, + BH::Item: Data, + BM: IntoIterator, + BM::Item: Data, + WH: IntoIterator, + WH::Item: Data, + WM: IntoIterator, + WM::Item: Data, + X: IntoIterator, + X::Item: Data, +{ + type Properties = Properties; + + fn plot<F>( + &mut self, + candlesticks: Candlesticks<X, WM, BM, BH, WH>, + configure: F, + ) -> &mut Figure + where + F: FnOnce(&mut Properties) -> &mut Properties, + { + let (x_factor, y_factor) = crate::scale_factor(&self.axes, crate::Axes::BottomXLeftY); + let Candlesticks { + x, + whisker_min, + box_min, + box_high, + whisker_high, + } = candlesticks; + + let data = Matrix::new( + izip!(x, box_min, whisker_min, whisker_high, box_high), + (x_factor, y_factor, y_factor, y_factor, y_factor), + ); + self.plots + .push(Plot::new(data, configure(&mut Default::default()))); + self + } +} diff --git a/vendor/criterion-plot/src/curve.rs b/vendor/criterion-plot/src/curve.rs new file mode 100755 index 000000000..a5766ee56 --- /dev/null +++ b/vendor/criterion-plot/src/curve.rs @@ -0,0 +1,273 @@ +//! Simple "curve" like plots + +use std::borrow::Cow; +use std::iter::IntoIterator; + +use crate::data::Matrix; +use crate::traits::{self, Data, Set}; +use crate::{ + Axes, Color, CurveDefault, Display, Figure, Label, LineType, LineWidth, Plot, PointSize, + PointType, Script, +}; + +/// Properties common to simple "curve" like plots +pub struct Properties { + axes: Option<Axes>, + color: Option<Color>, + label: Option<Cow<'static, str>>, + line_type: LineType, + linewidth: Option<f64>, + point_type: Option<PointType>, + point_size: Option<f64>, + style: Style, +} + +impl CurveDefault<Style> for Properties { + fn default(style: Style) -> Properties { + Properties { + axes: None, + color: None, + label: None, + line_type: LineType::Solid, + linewidth: None, + point_size: None, + point_type: None, + style, + } + } +} + +impl Script for Properties { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let mut script = if let Some(axes) = self.axes { + format!("axes {} ", axes.display()) + } else { + String::new() + }; + + script.push_str(&format!("with {} ", self.style.display())); + script.push_str(&format!("lt {} ", self.line_type.display())); + + if let Some(lw) = self.linewidth { + script.push_str(&format!("lw {} ", lw)) + } + + if let Some(color) = self.color { + script.push_str(&format!("lc rgb '{}' ", color.display())) + } + + if let Some(pt) = self.point_type { + script.push_str(&format!("pt {} ", pt.display())) + } + + if let Some(ps) = self.point_size { + script.push_str(&format!("ps {} ", ps)) + } + + if let Some(ref label) = self.label { + script.push_str("title '"); + script.push_str(label); + script.push('\'') + } else { + script.push_str("notitle") + } + + script + } +} + +impl Set<Axes> for Properties { + /// Select the axes to plot against + /// + /// **Note** By default, the `BottomXLeftY` axes are used + fn set(&mut self, axes: Axes) -> &mut Properties { + self.axes = Some(axes); + self + } +} + +impl Set<Color> for Properties { + /// Sets the line color + fn set(&mut self, color: Color) -> &mut Properties { + self.color = Some(color); + self + } +} + +impl Set<Label> for Properties { + /// Sets the legend label + fn set(&mut self, label: Label) -> &mut Properties { + self.label = Some(label.0); + self + } +} + +impl Set<LineType> for Properties { + /// Changes the line type + /// + /// **Note** By default `Solid` lines are used + fn set(&mut self, lt: LineType) -> &mut Properties { + self.line_type = lt; + self + } +} + +impl Set<LineWidth> for Properties { + /// Changes the width of the line + /// + /// # Panics + /// + /// Panics if `width` is a non-positive value + fn set(&mut self, lw: LineWidth) -> &mut Properties { + let lw = lw.0; + + assert!(lw > 0.); + + self.linewidth = Some(lw); + self + } +} + +impl Set<PointSize> for Properties { + /// Changes the size of the points + /// + /// # Panics + /// + /// Panics if `size` is a non-positive value + fn set(&mut self, ps: PointSize) -> &mut Properties { + let ps = ps.0; + + assert!(ps > 0.); + + self.point_size = Some(ps); + self + } +} + +impl Set<PointType> for Properties { + /// Changes the point type + fn set(&mut self, pt: PointType) -> &mut Properties { + self.point_type = Some(pt); + self + } +} + +/// Types of "curve" plots +pub enum Curve<X, Y> { + /// A minimally sized dot on each data point + Dots { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, + /// A vertical "impulse" on each data point + Impulses { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, + /// Line that joins the data points + Lines { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, + /// Line with a point on each data point + LinesPoints { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, + /// A point on each data point + Points { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, + /// An step `_|` between each data point + Steps { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + }, +} + +impl<X, Y> Curve<X, Y> { + fn style(&self) -> Style { + match *self { + Curve::Dots { .. } => Style::Dots, + Curve::Impulses { .. } => Style::Impulses, + Curve::Lines { .. } => Style::Lines, + Curve::LinesPoints { .. } => Style::LinesPoints, + Curve::Points { .. } => Style::Points, + Curve::Steps { .. } => Style::Steps, + } + } +} + +#[derive(Clone, Copy)] +enum Style { + Dots, + Impulses, + Lines, + LinesPoints, + Points, + Steps, +} + +impl Display<&'static str> for Style { + fn display(&self) -> &'static str { + match *self { + Style::Dots => "dots", + Style::Impulses => "impulses", + Style::Lines => "lines", + Style::LinesPoints => "linespoints", + Style::Points => "points", + Style::Steps => "steps", + } + } +} + +impl<X, Y> traits::Plot<Curve<X, Y>> for Figure +where + X: IntoIterator, + X::Item: Data, + Y: IntoIterator, + Y::Item: Data, +{ + type Properties = Properties; + + fn plot<F>(&mut self, curve: Curve<X, Y>, configure: F) -> &mut Figure + where + F: FnOnce(&mut Properties) -> &mut Properties, + { + let style = curve.style(); + let (x, y) = match curve { + Curve::Dots { x, y } + | Curve::Impulses { x, y } + | Curve::Lines { x, y } + | Curve::LinesPoints { x, y } + | Curve::Points { x, y } + | Curve::Steps { x, y } => (x, y), + }; + + let mut props = CurveDefault::default(style); + configure(&mut props); + + let (x_factor, y_factor) = + crate::scale_factor(&self.axes, props.axes.unwrap_or(crate::Axes::BottomXLeftY)); + + let data = Matrix::new(izip!(x, y), (x_factor, y_factor)); + self.plots.push(Plot::new(data, &props)); + self + } +} diff --git a/vendor/criterion-plot/src/data.rs b/vendor/criterion-plot/src/data.rs new file mode 100755 index 000000000..eb1f73864 --- /dev/null +++ b/vendor/criterion-plot/src/data.rs @@ -0,0 +1,174 @@ +#![allow(deprecated)] + +use std::mem; + +use cast::From as _0; + +use crate::traits::Data; + +macro_rules! impl_data { + ($($ty:ty),+) => { + $( + impl Data for $ty { + fn f64(self) -> f64 { + f64::cast(self) + } + } + + impl<'a> Data for &'a $ty { + fn f64(self) -> f64 { + f64::cast(*self) + } + } + )+ + } +} + +impl_data!(f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize); + +#[derive(Clone)] +pub struct Matrix { + bytes: Vec<u8>, + ncols: usize, + nrows: usize, +} + +impl Matrix { + pub fn new<I>(rows: I, scale: <I::Item as Row>::Scale) -> Matrix + where + I: Iterator, + I::Item: Row, + { + let ncols = I::Item::ncols(); + let bytes_per_row = ncols * mem::size_of::<f64>(); + let mut bytes = Vec::with_capacity(rows.size_hint().0 * bytes_per_row); + + let mut nrows = 0; + for row in rows { + nrows += 1; + row.append_to(&mut bytes, scale); + } + + Matrix { + bytes, + ncols, + nrows, + } + } + + pub fn bytes(&self) -> &[u8] { + &self.bytes + } + + pub fn ncols(&self) -> usize { + self.ncols + } + + pub fn nrows(&self) -> usize { + self.nrows + } +} + +/// Data that can serve as a row of the data matrix +pub trait Row { + /// Private + type Scale: Copy; + + /// Append this row to a buffer + fn append_to(self, buffer: &mut Vec<u8>, scale: Self::Scale); + /// Number of columns of the row + fn ncols() -> usize; +} + +fn write_f64(w: &mut impl std::io::Write, f: f64) -> std::io::Result<()> { + w.write_all(&f.to_bits().to_le_bytes()) +} + +impl<A, B> Row for (A, B) +where + A: Data, + B: Data, +{ + type Scale = (f64, f64); + + fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64)) { + let (a, b) = self; + + write_f64(buffer, a.f64() * scale.0).unwrap(); + write_f64(buffer, b.f64() * scale.1).unwrap(); + } + + fn ncols() -> usize { + 2 + } +} + +impl<A, B, C> Row for (A, B, C) +where + A: Data, + B: Data, + C: Data, +{ + type Scale = (f64, f64, f64); + + fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64)) { + let (a, b, c) = self; + + write_f64(buffer, a.f64() * scale.0).unwrap(); + write_f64(buffer, b.f64() * scale.1).unwrap(); + write_f64(buffer, c.f64() * scale.2).unwrap(); + } + + fn ncols() -> usize { + 3 + } +} + +impl<A, B, C, D> Row for (A, B, C, D) +where + A: Data, + B: Data, + C: Data, + D: Data, +{ + type Scale = (f64, f64, f64, f64); + + fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64)) { + let (a, b, c, d) = self; + + write_f64(buffer, a.f64() * scale.0).unwrap(); + write_f64(buffer, b.f64() * scale.1).unwrap(); + write_f64(buffer, c.f64() * scale.2).unwrap(); + write_f64(buffer, d.f64() * scale.3).unwrap(); + } + + fn ncols() -> usize { + 4 + } +} + +impl<A, B, C, D, E> Row for (A, B, C, D, E) +where + A: Data, + B: Data, + C: Data, + D: Data, + E: Data, +{ + type Scale = (f64, f64, f64, f64, f64); + + #[cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))] + fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64, f64)) { + let (a, b, c, d, e) = self; + + write_f64(buffer, a.f64() * scale.0).unwrap(); + write_f64(buffer, b.f64() * scale.1).unwrap(); + write_f64(buffer, c.f64() * scale.2).unwrap(); + write_f64(buffer, d.f64() * scale.3).unwrap(); + write_f64(buffer, e.f64() * scale.4).unwrap(); + } + + fn ncols() -> usize { + 5 + } +} diff --git a/vendor/criterion-plot/src/display.rs b/vendor/criterion-plot/src/display.rs new file mode 100755 index 000000000..8f6f1e130 --- /dev/null +++ b/vendor/criterion-plot/src/display.rs @@ -0,0 +1,139 @@ +use std::borrow::Cow; + +use crate::key::{Horizontal, Justification, Order, Stacked, Vertical}; +use crate::{Axes, Axis, Color, Display, Grid, LineType, PointType, Terminal}; + +impl Display<&'static str> for Axis { + fn display(&self) -> &'static str { + match *self { + Axis::BottomX => "x", + Axis::LeftY => "y", + Axis::RightY => "y2", + Axis::TopX => "x2", + } + } +} + +impl Display<&'static str> for Axes { + fn display(&self) -> &'static str { + match *self { + Axes::BottomXLeftY => "x1y1", + Axes::BottomXRightY => "x1y2", + Axes::TopXLeftY => "x2y1", + Axes::TopXRightY => "x2y2", + } + } +} + +impl Display<Cow<'static, str>> for Color { + fn display(&self) -> Cow<'static, str> { + match *self { + Color::Black => Cow::from("black"), + Color::Blue => Cow::from("blue"), + Color::Cyan => Cow::from("cyan"), + Color::DarkViolet => Cow::from("dark-violet"), + Color::ForestGreen => Cow::from("forest-green"), + Color::Gold => Cow::from("gold"), + Color::Gray => Cow::from("gray"), + Color::Green => Cow::from("green"), + Color::Magenta => Cow::from("magenta"), + Color::Red => Cow::from("red"), + Color::Rgb(r, g, b) => Cow::from(format!("#{:02x}{:02x}{:02x}", r, g, b)), + Color::White => Cow::from("white"), + Color::Yellow => Cow::from("yellow"), + } + } +} + +impl Display<&'static str> for Grid { + fn display(&self) -> &'static str { + match *self { + Grid::Major => "", + Grid::Minor => "m", + } + } +} + +impl Display<&'static str> for Horizontal { + fn display(&self) -> &'static str { + match *self { + Horizontal::Center => "center", + Horizontal::Left => "left", + Horizontal::Right => "right", + } + } +} + +impl Display<&'static str> for Justification { + fn display(&self) -> &'static str { + match *self { + Justification::Left => "Left", + Justification::Right => "Right", + } + } +} + +impl Display<&'static str> for LineType { + fn display(&self) -> &'static str { + match *self { + LineType::Dash => "2", + LineType::Dot => "3", + LineType::DotDash => "4", + LineType::DotDotDash => "5", + LineType::SmallDot => "0", + LineType::Solid => "1", + } + } +} + +impl Display<&'static str> for Order { + fn display(&self) -> &'static str { + match *self { + Order::TextSample => "noreverse", + Order::SampleText => "reverse", + } + } +} + +impl Display<&'static str> for PointType { + fn display(&self) -> &'static str { + match *self { + PointType::Circle => "6", + PointType::FilledCircle => "7", + PointType::FilledSquare => "5", + PointType::FilledTriangle => "9", + PointType::Plus => "1", + PointType::Square => "4", + PointType::Star => "3", + PointType::Triangle => "8", + PointType::X => "2", + } + } +} + +impl Display<&'static str> for Stacked { + fn display(&self) -> &'static str { + match *self { + Stacked::Horizontally => "horizontal", + Stacked::Vertically => "vertical", + } + } +} + +impl Display<&'static str> for Terminal { + fn display(&self) -> &'static str { + match *self { + Terminal::Svg => "svg dynamic", + } + } +} + +impl Display<&'static str> for Vertical { + fn display(&self) -> &'static str { + match *self { + Vertical::Bottom => "bottom", + Vertical::Center => "center", + Vertical::Top => "top", + } + } +} diff --git a/vendor/criterion-plot/src/errorbar.rs b/vendor/criterion-plot/src/errorbar.rs new file mode 100755 index 000000000..f7a823c5c --- /dev/null +++ b/vendor/criterion-plot/src/errorbar.rs @@ -0,0 +1,293 @@ +//! Error bar plots + +use std::borrow::Cow; +use std::iter::IntoIterator; + +use crate::data::Matrix; +use crate::traits::{self, Data, Set}; +use crate::{ + Color, Display, ErrorBarDefault, Figure, Label, LineType, LineWidth, Plot, PointSize, + PointType, Script, +}; + +/// Properties common to error bar plots +pub struct Properties { + color: Option<Color>, + label: Option<Cow<'static, str>>, + line_type: LineType, + linewidth: Option<f64>, + point_size: Option<f64>, + point_type: Option<PointType>, + style: Style, +} + +impl ErrorBarDefault<Style> for Properties { + fn default(style: Style) -> Properties { + Properties { + color: None, + label: None, + line_type: LineType::Solid, + linewidth: None, + point_type: None, + point_size: None, + style, + } + } +} + +impl Script for Properties { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let mut script = format!("with {} ", self.style.display()); + + script.push_str(&format!("lt {} ", self.line_type.display())); + + if let Some(lw) = self.linewidth { + script.push_str(&format!("lw {} ", lw)) + } + + if let Some(color) = self.color { + script.push_str(&format!("lc rgb '{}' ", color.display())) + } + + if let Some(pt) = self.point_type { + script.push_str(&format!("pt {} ", pt.display())) + } + + if let Some(ps) = self.point_size { + script.push_str(&format!("ps {} ", ps)) + } + + if let Some(ref label) = self.label { + script.push_str("title '"); + script.push_str(label); + script.push('\'') + } else { + script.push_str("notitle") + } + + script + } +} + +impl Set<Color> for Properties { + /// Changes the color of the error bars + fn set(&mut self, color: Color) -> &mut Properties { + self.color = Some(color); + self + } +} + +impl Set<Label> for Properties { + /// Sets the legend label + fn set(&mut self, label: Label) -> &mut Properties { + self.label = Some(label.0); + self + } +} + +impl Set<LineType> for Properties { + /// Change the line type + /// + /// **Note** By default `Solid` lines are used + fn set(&mut self, lt: LineType) -> &mut Properties { + self.line_type = lt; + self + } +} + +impl Set<LineWidth> for Properties { + /// Changes the linewidth + /// + /// # Panics + /// + /// Panics if `lw` is a non-positive value + fn set(&mut self, lw: LineWidth) -> &mut Properties { + let lw = lw.0; + + assert!(lw > 0.); + + self.linewidth = Some(lw); + self + } +} + +impl Set<PointSize> for Properties { + /// Changes the size of the points + /// + /// # Panics + /// + /// Panics if `size` is a non-positive value + fn set(&mut self, ps: PointSize) -> &mut Properties { + let ps = ps.0; + + assert!(ps > 0.); + + self.point_size = Some(ps); + self + } +} + +impl Set<PointType> for Properties { + /// Changes the point type + fn set(&mut self, pt: PointType) -> &mut Properties { + self.point_type = Some(pt); + self + } +} + +#[derive(Clone, Copy)] +enum Style { + XErrorBars, + XErrorLines, + YErrorBars, + YErrorLines, +} + +impl Display<&'static str> for Style { + fn display(&self) -> &'static str { + match *self { + Style::XErrorBars => "xerrorbars", + Style::XErrorLines => "xerrorlines", + Style::YErrorBars => "yerrorbars", + Style::YErrorLines => "yerrorlines", + } + } +} + +/// Asymmetric error bar plots +pub enum ErrorBar<X, Y, L, H> { + /// Horizontal error bars + XErrorBars { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + /// X coordinate of the left end of the error bar + x_low: L, + /// Y coordinate of the right end of the error bar + x_high: H, + }, + /// Horizontal error bars, where each point is joined by a line + XErrorLines { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + /// X coordinate of the left end of the error bar + x_low: L, + /// Y coordinate of the right end of the error bar + x_high: H, + }, + /// Vertical error bars + YErrorBars { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + /// Y coordinate of the bottom of the error bar + y_low: L, + /// Y coordinate of the top of the error bar + y_high: H, + }, + /// Vertical error bars, where each point is joined by a line + YErrorLines { + /// X coordinate of the data points + x: X, + /// Y coordinate of the data points + y: Y, + /// Y coordinate of the bottom of the error bar + y_low: L, + /// Y coordinate of the top of the error bar + y_high: H, + }, +} + +impl<X, Y, L, H> ErrorBar<X, Y, L, H> { + fn style(&self) -> Style { + match *self { + ErrorBar::XErrorBars { .. } => Style::XErrorBars, + ErrorBar::XErrorLines { .. } => Style::XErrorLines, + ErrorBar::YErrorBars { .. } => Style::YErrorBars, + ErrorBar::YErrorLines { .. } => Style::YErrorLines, + } + } +} + +impl<X, Y, L, H> traits::Plot<ErrorBar<X, Y, L, H>> for Figure +where + H: IntoIterator, + H::Item: Data, + L: IntoIterator, + L::Item: Data, + X: IntoIterator, + X::Item: Data, + Y: IntoIterator, + Y::Item: Data, +{ + type Properties = Properties; + + fn plot<F>(&mut self, e: ErrorBar<X, Y, L, H>, configure: F) -> &mut Figure + where + F: FnOnce(&mut Properties) -> &mut Properties, + { + let (x_factor, y_factor) = crate::scale_factor(&self.axes, crate::Axes::BottomXLeftY); + + let style = e.style(); + let (x, y, length, height, e_factor) = match e { + ErrorBar::XErrorBars { + x, + y, + x_low, + x_high, + } + | ErrorBar::XErrorLines { + x, + y, + x_low, + x_high, + } => (x, y, x_low, x_high, x_factor), + ErrorBar::YErrorBars { + x, + y, + y_low, + y_high, + } + | ErrorBar::YErrorLines { + x, + y, + y_low, + y_high, + } => (x, y, y_low, y_high, y_factor), + }; + let data = Matrix::new( + izip!(x, y, length, height), + (x_factor, y_factor, e_factor, e_factor), + ); + self.plots.push(Plot::new( + data, + configure(&mut ErrorBarDefault::default(style)), + )); + self + } +} + +// TODO XY error bar +// pub struct XyErrorBar<X, Y, XL, XH, YL, YH> { +// x: X, +// y: Y, +// x_low: XL, +// x_high: XH, +// y_low: YL, +// y_high: YH, +// } + +// TODO Symmetric error bars +// pub enum SymmetricErrorBar { +// XSymmetricErrorBar { x: X, y: Y, x_delta: D }, +// XSymmetricErrorLines { x: X, y: Y, x_delta: D }, +// YSymmetricErrorBar { x: X, y: Y, y_delta: D }, +// YSymmetricErrorLines { x: X, y: Y, y_delta: D }, +// } diff --git a/vendor/criterion-plot/src/filledcurve.rs b/vendor/criterion-plot/src/filledcurve.rs new file mode 100755 index 000000000..ab86099f9 --- /dev/null +++ b/vendor/criterion-plot/src/filledcurve.rs @@ -0,0 +1,143 @@ +//! Filled curve plots + +use std::borrow::Cow; +use std::iter::IntoIterator; + +use crate::data::Matrix; +use crate::traits::{self, Data, Set}; +use crate::{Axes, Color, Default, Display, Figure, Label, Opacity, Plot, Script}; + +/// Properties common to filled curve plots +pub struct Properties { + axes: Option<Axes>, + color: Option<Color>, + label: Option<Cow<'static, str>>, + opacity: Option<f64>, +} + +impl Default for Properties { + fn default() -> Properties { + Properties { + axes: None, + color: None, + label: None, + opacity: None, + } + } +} + +impl Script for Properties { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let mut script = if let Some(axes) = self.axes { + format!("axes {} ", axes.display()) + } else { + String::new() + }; + script.push_str("with filledcurves "); + + script.push_str("fillstyle "); + + if let Some(opacity) = self.opacity { + script.push_str(&format!("solid {} ", opacity)) + } + + // TODO border shoulde be configurable + script.push_str("noborder "); + + if let Some(color) = self.color { + script.push_str(&format!("lc rgb '{}' ", color.display())); + } + + if let Some(ref label) = self.label { + script.push_str("title '"); + script.push_str(label); + script.push('\'') + } else { + script.push_str("notitle") + } + + script + } +} + +impl Set<Axes> for Properties { + /// Select axes to plot against + /// + /// **Note** By default, the `BottomXLeftY` axes are used + fn set(&mut self, axes: Axes) -> &mut Properties { + self.axes = Some(axes); + self + } +} + +impl Set<Color> for Properties { + /// Sets the fill color + fn set(&mut self, color: Color) -> &mut Properties { + self.color = Some(color); + self + } +} + +impl Set<Label> for Properties { + /// Sets the legend label + fn set(&mut self, label: Label) -> &mut Properties { + self.label = Some(label.0); + self + } +} + +impl Set<Opacity> for Properties { + /// Changes the opacity of the fill color + /// + /// **Note** By default, the fill color is totally opaque (`opacity = 1.0`) + /// + /// # Panics + /// + /// Panics if `opacity` is outside the range `[0, 1]` + fn set(&mut self, opacity: Opacity) -> &mut Properties { + self.opacity = Some(opacity.0); + self + } +} + +/// Fills the area between two curves +pub struct FilledCurve<X, Y1, Y2> { + /// X coordinate of the data points of both curves + pub x: X, + /// Y coordinate of the data points of the first curve + pub y1: Y1, + /// Y coordinate of the data points of the second curve + pub y2: Y2, +} + +impl<X, Y1, Y2> traits::Plot<FilledCurve<X, Y1, Y2>> for Figure +where + X: IntoIterator, + X::Item: Data, + Y1: IntoIterator, + Y1::Item: Data, + Y2: IntoIterator, + Y2::Item: Data, +{ + type Properties = Properties; + + fn plot<F>(&mut self, fc: FilledCurve<X, Y1, Y2>, configure: F) -> &mut Figure + where + F: FnOnce(&mut Properties) -> &mut Properties, + { + let FilledCurve { x, y1, y2 } = fc; + + let mut props = Default::default(); + configure(&mut props); + + let (x_factor, y_factor) = + crate::scale_factor(&self.axes, props.axes.unwrap_or(crate::Axes::BottomXLeftY)); + + let data = Matrix::new(izip!(x, y1, y2), (x_factor, y_factor, y_factor)); + self.plots.push(Plot::new(data, &props)); + self + } +} diff --git a/vendor/criterion-plot/src/grid.rs b/vendor/criterion-plot/src/grid.rs new file mode 100755 index 000000000..b6adb2f11 --- /dev/null +++ b/vendor/criterion-plot/src/grid.rs @@ -0,0 +1,46 @@ +//! Gridline + +use crate::{Axis, Default, Display, Grid, Script}; + +/// Gridline properties +#[derive(Clone, Copy)] +pub struct Properties { + hidden: bool, +} + +impl Default for Properties { + fn default() -> Properties { + Properties { hidden: true } + } +} + +// TODO Lots of configuration pending: linetype, linewidth, etc +impl Properties { + /// Hides the gridlines + /// + /// **Note** Both `Major` and `Minor` gridlines are hidden by default + pub fn hide(&mut self) -> &mut Properties { + self.hidden = true; + self + } + + /// Shows the gridlines + pub fn show(&mut self) -> &mut Properties { + self.hidden = false; + self + } +} + +impl<'a> Script for (Axis, Grid, &'a Properties) { + fn script(&self) -> String { + let &(axis, grid, properties) = self; + let axis = axis.display(); + let grid = grid.display(); + + if properties.hidden { + String::new() + } else { + format!("set grid {}{}tics\n", grid, axis) + } + } +} diff --git a/vendor/criterion-plot/src/key.rs b/vendor/criterion-plot/src/key.rs new file mode 100755 index 000000000..dc27755ef --- /dev/null +++ b/vendor/criterion-plot/src/key.rs @@ -0,0 +1,221 @@ +//! Key (or legend) + +use std::borrow::Cow; + +use crate::traits::Set; +use crate::{Default, Display, Script, Title}; + +/// Properties of the key +#[derive(Clone)] +pub struct Properties { + boxed: bool, + hidden: bool, + justification: Option<Justification>, + order: Option<Order>, + position: Option<Position>, + stacked: Option<Stacked>, + title: Option<Cow<'static, str>>, +} + +impl Default for Properties { + fn default() -> Properties { + Properties { + boxed: false, + hidden: false, + justification: None, + order: None, + position: None, + stacked: None, + title: None, + } + } +} + +impl Properties { + /// Hides the key + pub fn hide(&mut self) -> &mut Properties { + self.hidden = true; + self + } + + /// Shows the key + /// + /// **Note** The key is shown by default + pub fn show(&mut self) -> &mut Properties { + self.hidden = false; + self + } +} + +impl Script for Properties { + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> String { + let mut script = if self.hidden { + return String::from("set key off\n"); + } else { + String::from("set key on ") + }; + + match self.position { + None => {} + Some(Position::Inside(v, h)) => { + script.push_str(&format!("inside {} {} ", v.display(), h.display())) + } + Some(Position::Outside(v, h)) => { + script.push_str(&format!("outside {} {} ", v.display(), h.display())) + } + } + + if let Some(stacked) = self.stacked { + script.push_str(stacked.display()); + script.push(' '); + } + + if let Some(justification) = self.justification { + script.push_str(justification.display()); + script.push(' '); + } + + if let Some(order) = self.order { + script.push_str(order.display()); + script.push(' '); + } + + if let Some(ref title) = self.title { + script.push_str(&format!("title '{}' ", title)) + } + + if self.boxed { + script.push_str("box ") + } + + script.push('\n'); + script + } +} + +impl Set<Boxed> for Properties { + /// Select if the key will be surrounded with a box or not + /// + /// **Note** The key is not boxed by default + fn set(&mut self, boxed: Boxed) -> &mut Properties { + match boxed { + Boxed::No => self.boxed = false, + Boxed::Yes => self.boxed = true, + } + + self + } +} + +impl Set<Justification> for Properties { + /// Changes the justification of the text of each entry + /// + /// **Note** The text is `RightJustified` by default + fn set(&mut self, justification: Justification) -> &mut Properties { + self.justification = Some(justification); + self + } +} + +impl Set<Order> for Properties { + /// How to order each entry + /// + /// **Note** The default order is `TextSample` + fn set(&mut self, order: Order) -> &mut Properties { + self.order = Some(order); + self + } +} + +impl Set<Position> for Properties { + /// Selects where to place the key + /// + /// **Note** By default, the key is placed `Inside(Vertical::Top, Horizontal::Right)` + fn set(&mut self, position: Position) -> &mut Properties { + self.position = Some(position); + self + } +} + +impl Set<Stacked> for Properties { + /// Changes how the entries of the key are stacked + fn set(&mut self, stacked: Stacked) -> &mut Properties { + self.stacked = Some(stacked); + self + } +} + +impl Set<Title> for Properties { + fn set(&mut self, title: Title) -> &mut Properties { + self.title = Some(title.0); + self + } +} + +/// Whether the key is surrounded by a box or not +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Boxed { + No, + Yes, +} + +/// Horizontal position of the key +#[derive(Clone, Copy)] +pub enum Horizontal { + /// Center of the figure + Center, + /// Left border of the figure + Left, + /// Right border of the figure + Right, +} + +/// Text justification of the key +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Justification { + Left, + Right, +} + +/// Order of the elements of the key +#[derive(Clone, Copy)] +pub enum Order { + /// Sample first, then text + SampleText, + /// Text first, then sample + TextSample, +} + +/// Position of the key +// TODO XY position +#[derive(Clone, Copy)] +pub enum Position { + /// Inside the area surrounded by the four (BottomX, TopX, LeftY and RightY) axes + Inside(Vertical, Horizontal), + /// Outside of that area + Outside(Vertical, Horizontal), +} + +/// How the entries of the key are stacked +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Stacked { + Horizontally, + Vertically, +} + +/// Vertical position of the key +#[derive(Clone, Copy)] +pub enum Vertical { + /// Bottom border of the figure + Bottom, + /// Center of the figure + Center, + /// Top border of the figure + Top, +} diff --git a/vendor/criterion-plot/src/lib.rs b/vendor/criterion-plot/src/lib.rs new file mode 100755 index 000000000..be511058d --- /dev/null +++ b/vendor/criterion-plot/src/lib.rs @@ -0,0 +1,1093 @@ +//! [Criterion]'s plotting library. +//! +//! [Criterion]: https://github.com/bheisler/criterion.rs +//! +//! **WARNING** This library is criterion's implementation detail and there no plans to stabilize +//! it. In other words, the API may break at any time without notice. +//! +//! # Examples +//! +//! - Simple "curves" (based on [`simple.dem`](http://gnuplot.sourceforge.net/demo/simple.html)) +//! +//! ![Plot](curve.svg) +//! +//! ``` +//! # use std::fs; +//! # use std::path::Path; +//! use itertools_num::linspace; +//! use criterion_plot::prelude::*; +//! +//! # if let Err(_) = criterion_plot::version() { +//! # return; +//! # } +//! let ref xs = linspace::<f64>(-10., 10., 51).collect::<Vec<_>>(); +//! +//! # fs::create_dir_all(Path::new("target/doc/criterion_plot")).unwrap(); +//! # assert_eq!(Some(String::new()), +//! Figure::new() +//! # .set(Font("Helvetica")) +//! # .set(FontSize(12.)) +//! # .set(Output(Path::new("target/doc/criterion_plot/curve.svg"))) +//! # .set(Size(1280, 720)) +//! .configure(Key, |k| { +//! k.set(Boxed::Yes) +//! .set(Position::Inside(Vertical::Top, Horizontal::Left)) +//! }) +//! .plot(LinesPoints { +//! x: xs, +//! y: xs.iter().map(|x| x.sin()), +//! }, +//! |lp| { +//! lp.set(Color::DarkViolet) +//! .set(Label("sin(x)")) +//! .set(LineType::Dash) +//! .set(PointSize(1.5)) +//! .set(PointType::Circle) +//! }) +//! .plot(Steps { +//! x: xs, +//! y: xs.iter().map(|x| x.atan()), +//! }, +//! |s| { +//! s.set(Color::Rgb(0, 158, 115)) +//! .set(Label("atan(x)")) +//! .set(LineWidth(2.)) +//! }) +//! .plot(Impulses { +//! x: xs, +//! y: xs.iter().map(|x| x.atan().cos()), +//! }, +//! |i| { +//! i.set(Color::Rgb(86, 180, 233)) +//! .set(Label("cos(atan(x))")) +//! }) +//! .draw() // (rest of the chain has been omitted) +//! # .ok() +//! # .and_then(|gnuplot| { +//! # gnuplot.wait_with_output().ok().and_then(|p| String::from_utf8(p.stderr).ok()) +//! # })); +//! ``` +//! +//! - error bars (based on +//! [Julia plotting tutorial](https://plot.ly/julia/error-bars/#Colored-and-Styled-Error-Bars)) +//! +//! ![Plot](error_bar.svg) +//! +//! ``` +//! # use std::fs; +//! # use std::path::Path; +//! use std::f64::consts::PI; +//! +//! use itertools_num::linspace; +//! use rand::Rng; +//! use criterion_plot::prelude::*; +//! +//! fn sinc(mut x: f64) -> f64 { +//! if x == 0. { +//! 1. +//! } else { +//! x *= PI; +//! x.sin() / x +//! } +//! } +//! +//! # if let Err(_) = criterion_plot::version() { +//! # return; +//! # } +//! let ref xs_ = linspace::<f64>(-4., 4., 101).collect::<Vec<_>>(); +//! +//! // Fake some data +//! let ref mut rng = rand::thread_rng(); +//! let xs = linspace::<f64>(-4., 4., 13).skip(1).take(11); +//! let ys = xs.map(|x| sinc(x) + 0.05 * rng.gen::<f64>() - 0.025).collect::<Vec<_>>(); +//! let y_low = ys.iter().map(|&y| y - 0.025 - 0.075 * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let y_high = ys.iter().map(|&y| y + 0.025 + 0.075 * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let xs = linspace::<f64>(-4., 4., 13).skip(1).take(11); +//! let xs = xs.map(|x| x + 0.2 * rng.gen::<f64>() - 0.1); +//! +//! # fs::create_dir_all(Path::new("target/doc/criterion_plot")).unwrap(); +//! # assert_eq!(Some(String::new()), +//! Figure::new() +//! # .set(Font("Helvetica")) +//! # .set(FontSize(12.)) +//! # .set(Output(Path::new("target/doc/criterion_plot/error_bar.svg"))) +//! # .set(Size(1280, 720)) +//! .configure(Axis::BottomX, |a| { +//! a.set(TicLabels { +//! labels: &["-π", "0", "π"], +//! positions: &[-PI, 0., PI], +//! }) +//! }) +//! .configure(Key, +//! |k| k.set(Position::Outside(Vertical::Top, Horizontal::Right))) +//! .plot(Lines { +//! x: xs_, +//! y: xs_.iter().cloned().map(sinc), +//! }, +//! |l| { +//! l.set(Color::Rgb(0, 158, 115)) +//! .set(Label("sinc(x)")) +//! .set(LineWidth(2.)) +//! }) +//! .plot(YErrorBars { +//! x: xs, +//! y: &ys, +//! y_low: &y_low, +//! y_high: &y_high, +//! }, +//! |eb| { +//! eb.set(Color::DarkViolet) +//! .set(LineWidth(2.)) +//! .set(PointType::FilledCircle) +//! .set(Label("measured")) +//! }) +//! .draw() // (rest of the chain has been omitted) +//! # .ok() +//! # .and_then(|gnuplot| { +//! # gnuplot.wait_with_output().ok().and_then(|p| String::from_utf8(p.stderr).ok()) +//! # })); +//! ``` +//! +//! - Candlesticks (based on +//! [`candlesticks.dem`](http://gnuplot.sourceforge.net/demo/candlesticks.html)) +//! +//! ![Plot](candlesticks.svg) +//! +//! ``` +//! # use std::fs; +//! # use std::path::Path; +//! use criterion_plot::prelude::*; +//! use rand::Rng; +//! +//! # if let Err(_) = criterion_plot::version() { +//! # return; +//! # } +//! let xs = 1..11; +//! +//! // Fake some data +//! let mut rng = rand::thread_rng(); +//! let bh = xs.clone().map(|_| 5f64 + 2.5 * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let bm = xs.clone().map(|_| 2.5f64 + 2.5 * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let wh = bh.iter().map(|&y| y + (10. - y) * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let wm = bm.iter().map(|&y| y * rng.gen::<f64>()).collect::<Vec<_>>(); +//! let m = bm.iter().zip(bh.iter()).map(|(&l, &h)| (h - l) * rng.gen::<f64>() + l) +//! .collect::<Vec<_>>(); +//! +//! # fs::create_dir_all(Path::new("target/doc/criterion_plot")).unwrap(); +//! # assert_eq!(Some(String::new()), +//! Figure::new() +//! # .set(Font("Helvetica")) +//! # .set(FontSize(12.)) +//! # .set(Output(Path::new("target/doc/criterion_plot/candlesticks.svg"))) +//! # .set(Size(1280, 720)) +//! .set(BoxWidth(0.2)) +//! .configure(Axis::BottomX, |a| a.set(Range::Limits(0., 11.))) +//! .plot(Candlesticks { +//! x: xs.clone(), +//! whisker_min: &wm, +//! box_min: &bm, +//! box_high: &bh, +//! whisker_high: &wh, +//! }, +//! |cs| { +//! cs.set(Color::Rgb(86, 180, 233)) +//! .set(Label("Quartiles")) +//! .set(LineWidth(2.)) +//! }) +//! // trick to plot the median +//! .plot(Candlesticks { +//! x: xs, +//! whisker_min: &m, +//! box_min: &m, +//! box_high: &m, +//! whisker_high: &m, +//! }, +//! |cs| { +//! cs.set(Color::Black) +//! .set(LineWidth(2.)) +//! }) +//! .draw() // (rest of the chain has been omitted) +//! # .ok() +//! # .and_then(|gnuplot| { +//! # gnuplot.wait_with_output().ok().and_then(|p| String::from_utf8(p.stderr).ok()) +//! # })); +//! ``` +//! +//! - Multiaxis (based on [`multiaxis.dem`](http://gnuplot.sourceforge.net/demo/multiaxis.html)) +//! +//! ![Plot](multiaxis.svg) +//! +//! ``` +//! # use std::fs; +//! # use std::path::Path; +//! use std::f64::consts::PI; +//! +//! use itertools_num::linspace; +//! use num_complex::Complex; +//! use criterion_plot::prelude::*; +//! +//! fn tf(x: f64) -> Complex<f64> { +//! Complex::new(0., x) / Complex::new(10., x) / Complex::new(1., x / 10_000.) +//! } +//! +//! # if let Err(_) = criterion_plot::version() { +//! # return; +//! # } +//! let (start, end): (f64, f64) = (1.1, 90_000.); +//! let ref xs = linspace(start.ln(), end.ln(), 101).map(|x| x.exp()).collect::<Vec<_>>(); +//! let phase = xs.iter().map(|&x| tf(x).arg() * 180. / PI); +//! let magnitude = xs.iter().map(|&x| tf(x).norm()); +//! +//! # fs::create_dir_all(Path::new("target/doc/criterion_plot")).unwrap(); +//! # assert_eq!(Some(String::new()), +//! Figure::new(). +//! # set(Font("Helvetica")). +//! # set(FontSize(12.)). +//! # set(Output(Path::new("target/doc/criterion_plot/multiaxis.svg"))). +//! # set(Size(1280, 720)). +//! set(Title("Frequency response")). +//! configure(Axis::BottomX, |a| a. +//! configure(Grid::Major, |g| g. +//! show()). +//! set(Label("Angular frequency (rad/s)")). +//! set(Range::Limits(start, end)). +//! set(Scale::Logarithmic)). +//! configure(Axis::LeftY, |a| a. +//! set(Label("Gain")). +//! set(Scale::Logarithmic)). +//! configure(Axis::RightY, |a| a. +//! configure(Grid::Major, |g| g. +//! show()). +//! set(Label("Phase shift (°)"))). +//! configure(Key, |k| k. +//! set(Position::Inside(Vertical::Top, Horizontal::Center)). +//! set(Title(" "))). +//! plot(Lines { +//! x: xs, +//! y: magnitude, +//! }, |l| l. +//! set(Color::DarkViolet). +//! set(Label("Magnitude")). +//! set(LineWidth(2.))). +//! plot(Lines { +//! x: xs, +//! y: phase, +//! }, |l| l. +//! set(Axes::BottomXRightY). +//! set(Color::Rgb(0, 158, 115)). +//! set(Label("Phase")). +//! set(LineWidth(2.))). +//! draw(). // (rest of the chain has been omitted) +//! # ok().and_then(|gnuplot| { +//! # gnuplot.wait_with_output().ok().and_then(|p| { +//! # String::from_utf8(p.stderr).ok() +//! # }) +//! # })); +//! ``` +//! - Filled curves (based on +//! [`transparent.dem`](http://gnuplot.sourceforge.net/demo/transparent.html)) +//! +//! ![Plot](filled_curve.svg) +//! +//! ``` +//! # use std::fs; +//! # use std::path::Path; +//! use std::f64::consts::PI; +//! use std::iter; +//! +//! use itertools_num::linspace; +//! use criterion_plot::prelude::*; +//! +//! # if let Err(_) = criterion_plot::version() { +//! # return; +//! # } +//! let (start, end) = (-5., 5.); +//! let ref xs = linspace(start, end, 101).collect::<Vec<_>>(); +//! let zeros = iter::repeat(0); +//! +//! fn gaussian(x: f64, mu: f64, sigma: f64) -> f64 { +//! 1. / (((x - mu).powi(2) / 2. / sigma.powi(2)).exp() * sigma * (2. * PI).sqrt()) +//! } +//! +//! # fs::create_dir_all(Path::new("target/doc/criterion_plot")).unwrap(); +//! # assert_eq!(Some(String::new()), +//! Figure::new() +//! # .set(Font("Helvetica")) +//! # .set(FontSize(12.)) +//! # .set(Output(Path::new("target/doc/criterion_plot/filled_curve.svg"))) +//! # .set(Size(1280, 720)) +//! .set(Title("Transparent filled curve")) +//! .configure(Axis::BottomX, |a| a.set(Range::Limits(start, end))) +//! .configure(Axis::LeftY, |a| a.set(Range::Limits(0., 1.))) +//! .configure(Key, |k| { +//! k.set(Justification::Left) +//! .set(Order::SampleText) +//! .set(Position::Inside(Vertical::Top, Horizontal::Left)) +//! .set(Title("Gaussian Distribution")) +//! }) +//! .plot(FilledCurve { +//! x: xs, +//! y1: xs.iter().map(|&x| gaussian(x, 0.5, 0.5)), +//! y2: zeros.clone(), +//! }, +//! |fc| { +//! fc.set(Color::ForestGreen) +//! .set(Label("μ = 0.5 σ = 0.5")) +//! }) +//! .plot(FilledCurve { +//! x: xs, +//! y1: xs.iter().map(|&x| gaussian(x, 2.0, 1.0)), +//! y2: zeros.clone(), +//! }, +//! |fc| { +//! fc.set(Color::Gold) +//! .set(Label("μ = 2.0 σ = 1.0")) +//! .set(Opacity(0.5)) +//! }) +//! .plot(FilledCurve { +//! x: xs, +//! y1: xs.iter().map(|&x| gaussian(x, -1.0, 2.0)), +//! y2: zeros, +//! }, +//! |fc| { +//! fc.set(Color::Red) +//! .set(Label("μ = -1.0 σ = 2.0")) +//! .set(Opacity(0.5)) +//! }) +//! .draw() +//! .ok() +//! .and_then(|gnuplot| { +//! gnuplot.wait_with_output().ok().and_then(|p| String::from_utf8(p.stderr).ok()) +//! })); +//! ``` + +#![deny(missing_docs)] +#![deny(warnings)] +#![deny(bare_trait_objects)] +// This lint has lots of false positives ATM, see +// https://github.com/Manishearth/rust-clippy/issues/761 +#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] +// False positives with images +#![cfg_attr(feature = "cargo-clippy", allow(clippy::doc_markdown))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))] + +extern crate cast; +#[macro_use] +extern crate itertools; + +use std::borrow::Cow; +use std::fmt; +use std::fs::File; +use std::io; +use std::num::ParseIntError; +use std::path::Path; +use std::process::{Child, Command}; +use std::str; + +use crate::data::Matrix; +use crate::traits::{Configure, Set}; + +mod data; +mod display; +mod map; + +pub mod axis; +pub mod candlestick; +pub mod curve; +pub mod errorbar; +pub mod filledcurve; +pub mod grid; +pub mod key; +pub mod prelude; +pub mod proxy; +pub mod traits; + +/// Plot container +#[derive(Clone)] +pub struct Figure { + alpha: Option<f64>, + axes: map::axis::Map<axis::Properties>, + box_width: Option<f64>, + font: Option<Cow<'static, str>>, + font_size: Option<f64>, + key: Option<key::Properties>, + output: Cow<'static, Path>, + plots: Vec<Plot>, + size: Option<(usize, usize)>, + terminal: Terminal, + tics: map::axis::Map<String>, + title: Option<Cow<'static, str>>, +} + +impl Figure { + /// Creates an empty figure + pub fn new() -> Figure { + Figure { + alpha: None, + axes: map::axis::Map::new(), + box_width: None, + font: None, + font_size: None, + key: None, + output: Cow::Borrowed(Path::new("output.plot")), + plots: Vec::new(), + size: None, + terminal: Terminal::Svg, + tics: map::axis::Map::new(), + title: None, + } + } + + // Allow clippy::format_push_string even with older versions of rust (<1.62) which + // don't have it defined. + #[allow(clippy::all)] + fn script(&self) -> Vec<u8> { + let mut s = String::new(); + + s.push_str(&format!( + "set output '{}'\n", + self.output.display().to_string().replace('\'', "''") + )); + + if let Some(width) = self.box_width { + s.push_str(&format!("set boxwidth {}\n", width)) + } + + if let Some(ref title) = self.title { + s.push_str(&format!("set title '{}'\n", title)) + } + + for axis in self.axes.iter() { + s.push_str(&axis.script()); + } + + for (_, script) in self.tics.iter() { + s.push_str(script); + } + + if let Some(ref key) = self.key { + s.push_str(&key.script()) + } + + if let Some(alpha) = self.alpha { + s.push_str(&format!("set style fill transparent solid {}\n", alpha)) + } + + s.push_str(&format!("set terminal {} dashed", self.terminal.display())); + + if let Some((width, height)) = self.size { + s.push_str(&format!(" size {}, {}", width, height)) + } + + if let Some(ref name) = self.font { + if let Some(size) = self.font_size { + s.push_str(&format!(" font '{},{}'", name, size)) + } else { + s.push_str(&format!(" font '{}'", name)) + } + } + + // TODO This removes the crossbars from the ends of error bars, but should be configurable + s.push_str("\nunset bars\n"); + + let mut is_first_plot = true; + for plot in &self.plots { + let data = plot.data(); + + if data.bytes().is_empty() { + continue; + } + + if is_first_plot { + s.push_str("plot "); + is_first_plot = false; + } else { + s.push_str(", "); + } + + s.push_str(&format!( + "'-' binary endian=little record={} format='%float64' using ", + data.nrows() + )); + + let mut is_first_col = true; + for col in 0..data.ncols() { + if is_first_col { + is_first_col = false; + } else { + s.push(':'); + } + s.push_str(&(col + 1).to_string()); + } + s.push(' '); + + s.push_str(plot.script()); + } + + let mut buffer = s.into_bytes(); + let mut is_first = true; + for plot in &self.plots { + if is_first { + is_first = false; + buffer.push(b'\n'); + } + buffer.extend_from_slice(plot.data().bytes()); + } + + buffer + } + + /// Spawns a drawing child process + /// + /// NOTE: stderr, stdin, and stdout are piped + pub fn draw(&mut self) -> io::Result<Child> { + use std::process::Stdio; + + let mut gnuplot = Command::new("gnuplot") + .stderr(Stdio::piped()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + self.dump(gnuplot.stdin.as_mut().unwrap())?; + Ok(gnuplot) + } + + /// Dumps the script required to produce the figure into `sink` + pub fn dump<W>(&mut self, sink: &mut W) -> io::Result<&mut Figure> + where + W: io::Write, + { + sink.write_all(&self.script())?; + Ok(self) + } + + /// Saves the script required to produce the figure to `path` + pub fn save(&self, path: &Path) -> io::Result<&Figure> { + use std::io::Write; + + File::create(path)?.write_all(&self.script())?; + Ok(self) + } +} + +impl Configure<Axis> for Figure { + type Properties = axis::Properties; + + /// Configures an axis + fn configure<F>(&mut self, axis: Axis, configure: F) -> &mut Figure + where + F: FnOnce(&mut axis::Properties) -> &mut axis::Properties, + { + if self.axes.contains_key(axis) { + configure(self.axes.get_mut(axis).unwrap()); + } else { + let mut properties = Default::default(); + configure(&mut properties); + self.axes.insert(axis, properties); + } + self + } +} + +impl Configure<Key> for Figure { + type Properties = key::Properties; + + /// Configures the key (legend) + fn configure<F>(&mut self, _: Key, configure: F) -> &mut Figure + where + F: FnOnce(&mut key::Properties) -> &mut key::Properties, + { + if self.key.is_some() { + configure(self.key.as_mut().unwrap()); + } else { + let mut key = Default::default(); + configure(&mut key); + self.key = Some(key); + } + self + } +} + +impl Set<BoxWidth> for Figure { + /// Changes the box width of all the box related plots (bars, candlesticks, etc) + /// + /// **Note** The default value is 0 + /// + /// # Panics + /// + /// Panics if `width` is a negative value + fn set(&mut self, width: BoxWidth) -> &mut Figure { + let width = width.0; + + assert!(width >= 0.); + + self.box_width = Some(width); + self + } +} + +impl Set<Font> for Figure { + /// Changes the font + fn set(&mut self, font: Font) -> &mut Figure { + self.font = Some(font.0); + self + } +} + +impl Set<FontSize> for Figure { + /// Changes the size of the font + /// + /// # Panics + /// + /// Panics if `size` is a non-positive value + fn set(&mut self, size: FontSize) -> &mut Figure { + let size = size.0; + + assert!(size >= 0.); + + self.font_size = Some(size); + self + } +} + +impl Set<Output> for Figure { + /// Changes the output file + /// + /// **Note** The default output file is `output.plot` + fn set(&mut self, output: Output) -> &mut Figure { + self.output = output.0; + self + } +} + +impl Set<Size> for Figure { + /// Changes the figure size + fn set(&mut self, size: Size) -> &mut Figure { + self.size = Some((size.0, size.1)); + self + } +} + +impl Set<Terminal> for Figure { + /// Changes the output terminal + /// + /// **Note** By default, the terminal is set to `Svg` + fn set(&mut self, terminal: Terminal) -> &mut Figure { + self.terminal = terminal; + self + } +} + +impl Set<Title> for Figure { + /// Sets the title + fn set(&mut self, title: Title) -> &mut Figure { + self.title = Some(title.0); + self + } +} + +impl Default for Figure { + fn default() -> Self { + Self::new() + } +} + +/// Box width for box-related plots: bars, candlesticks, etc +#[derive(Clone, Copy)] +pub struct BoxWidth(pub f64); + +/// A font name +pub struct Font(Cow<'static, str>); + +/// The size of a font +#[derive(Clone, Copy)] +pub struct FontSize(pub f64); + +/// The key or legend +#[derive(Clone, Copy)] +pub struct Key; + +/// Plot label +pub struct Label(Cow<'static, str>); + +/// Width of the lines +#[derive(Clone, Copy)] +pub struct LineWidth(pub f64); + +/// Fill color opacity +#[derive(Clone, Copy)] +pub struct Opacity(pub f64); + +/// Output file path +pub struct Output(Cow<'static, Path>); + +/// Size of the points +#[derive(Clone, Copy)] +pub struct PointSize(pub f64); + +/// Axis range +#[derive(Clone, Copy)] +pub enum Range { + /// Autoscale the axis + Auto, + /// Set the limits of the axis + Limits(f64, f64), +} + +/// Figure size +#[derive(Clone, Copy)] +pub struct Size(pub usize, pub usize); + +/// Labels attached to the tics of an axis +pub struct TicLabels<P, L> { + /// Labels to attach to the tics + pub labels: L, + /// Position of the tics on the axis + pub positions: P, +} + +/// Figure title +pub struct Title(Cow<'static, str>); + +/// A pair of axes that define a coordinate system +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Axes { + BottomXLeftY, + BottomXRightY, + TopXLeftY, + TopXRightY, +} + +/// A coordinate axis +#[derive(Clone, Copy)] +pub enum Axis { + /// X axis on the bottom side of the figure + BottomX, + /// Y axis on the left side of the figure + LeftY, + /// Y axis on the right side of the figure + RightY, + /// X axis on the top side of the figure + TopX, +} + +impl Axis { + fn next(self) -> Option<Axis> { + use crate::Axis::*; + + match self { + BottomX => Some(LeftY), + LeftY => Some(RightY), + RightY => Some(TopX), + TopX => None, + } + } +} + +/// Color +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Color { + Black, + Blue, + Cyan, + DarkViolet, + ForestGreen, + Gold, + Gray, + Green, + Magenta, + Red, + /// Custom RGB color + Rgb(u8, u8, u8), + White, + Yellow, +} + +/// Grid line +#[derive(Clone, Copy)] +pub enum Grid { + /// Major gridlines + Major, + /// Minor gridlines + Minor, +} + +impl Grid { + fn next(self) -> Option<Grid> { + use crate::Grid::*; + + match self { + Major => Some(Minor), + Minor => None, + } + } +} + +/// Line type +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum LineType { + Dash, + Dot, + DotDash, + DotDotDash, + /// Line made of minimally sized dots + SmallDot, + Solid, +} + +/// Point type +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum PointType { + Circle, + FilledCircle, + FilledSquare, + FilledTriangle, + Plus, + Square, + Star, + Triangle, + X, +} + +/// Axis scale +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Scale { + Linear, + Logarithmic, +} + +/// Axis scale factor +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub struct ScaleFactor(pub f64); + +/// Output terminal +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum Terminal { + Svg, +} + +/// Not public version of `std::default::Default`, used to not leak default constructors into the +/// public API +trait Default { + /// Creates `Properties` with default configuration + fn default() -> Self; +} + +/// Enums that can produce gnuplot code +trait Display<S> { + /// Translates the enum in gnuplot code + fn display(&self) -> S; +} + +/// Curve variant of Default +trait CurveDefault<S> { + /// Creates `curve::Properties` with default configuration + fn default(s: S) -> Self; +} + +/// Error bar variant of Default +trait ErrorBarDefault<S> { + /// Creates `errorbar::Properties` with default configuration + fn default(s: S) -> Self; +} + +/// Structs that can produce gnuplot code +trait Script { + /// Translates some configuration struct into gnuplot code + fn script(&self) -> String; +} + +#[derive(Clone)] +struct Plot { + data: Matrix, + script: String, +} + +impl Plot { + fn new<S>(data: Matrix, script: &S) -> Plot + where + S: Script, + { + Plot { + data, + script: script.script(), + } + } + + fn data(&self) -> &Matrix { + &self.data + } + + fn script(&self) -> &str { + &self.script + } +} + +/// Possible errors when parsing gnuplot's version string +#[derive(Debug)] +pub enum VersionError { + /// The `gnuplot` command couldn't be executed + Exec(io::Error), + /// The `gnuplot` command returned an error message + Error(String), + /// The `gnuplot` command returned invalid utf-8 + OutputError, + /// The `gnuplot` command returned an unparseable string + ParseError(String), +} +impl fmt::Display for VersionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VersionError::Exec(err) => write!(f, "`gnuplot --version` failed: {}", err), + VersionError::Error(msg) => { + write!(f, "`gnuplot --version` failed with error message:\n{}", msg) + } + VersionError::OutputError => write!(f, "`gnuplot --version` returned invalid utf-8"), + VersionError::ParseError(msg) => write!( + f, + "`gnuplot --version` returned an unparseable version string: {}", + msg + ), + } + } +} +impl ::std::error::Error for VersionError { + fn description(&self) -> &str { + match self { + VersionError::Exec(_) => "Execution Error", + VersionError::Error(_) => "Other Error", + VersionError::OutputError => "Output Error", + VersionError::ParseError(_) => "Parse Error", + } + } + + fn cause(&self) -> Option<&dyn ::std::error::Error> { + match self { + VersionError::Exec(err) => Some(err), + _ => None, + } + } +} + +/// Structure representing a gnuplot version number. +pub struct Version { + /// The major version number + pub major: usize, + /// The minor version number + pub minor: usize, + /// The patch level + pub patch: String, +} + +/// Returns `gnuplot` version +pub fn version() -> Result<Version, VersionError> { + let command_output = Command::new("gnuplot") + .arg("--version") + .output() + .map_err(VersionError::Exec)?; + if !command_output.status.success() { + let error = + String::from_utf8(command_output.stderr).map_err(|_| VersionError::OutputError)?; + return Err(VersionError::Error(error)); + } + + let output = String::from_utf8(command_output.stdout).map_err(|_| VersionError::OutputError)?; + + parse_version(&output).map_err(|_| VersionError::ParseError(output.clone())) +} + +fn parse_version(version_str: &str) -> Result<Version, Option<ParseIntError>> { + let mut words = version_str.split_whitespace().skip(1); + let mut version = words.next().ok_or(None)?.split('.'); + let major = version.next().ok_or(None)?.parse()?; + let minor = version.next().ok_or(None)?.parse()?; + let patchlevel = words.nth(1).ok_or(None)?.to_owned(); + + Ok(Version { + major, + minor, + patch: patchlevel, + }) +} + +fn scale_factor(map: &map::axis::Map<axis::Properties>, axes: Axes) -> (f64, f64) { + use crate::Axes::*; + use crate::Axis::*; + + match axes { + BottomXLeftY => ( + map.get(BottomX).map_or(1., ScaleFactorTrait::scale_factor), + map.get(LeftY).map_or(1., ScaleFactorTrait::scale_factor), + ), + BottomXRightY => ( + map.get(BottomX).map_or(1., ScaleFactorTrait::scale_factor), + map.get(RightY).map_or(1., ScaleFactorTrait::scale_factor), + ), + TopXLeftY => ( + map.get(TopX).map_or(1., ScaleFactorTrait::scale_factor), + map.get(LeftY).map_or(1., ScaleFactorTrait::scale_factor), + ), + TopXRightY => ( + map.get(TopX).map_or(1., ScaleFactorTrait::scale_factor), + map.get(RightY).map_or(1., ScaleFactorTrait::scale_factor), + ), + } +} + +// XXX :-1: to intra-crate privacy rules +/// Private +trait ScaleFactorTrait { + /// Private + fn scale_factor(&self) -> f64; +} + +#[cfg(test)] +mod test { + #[test] + fn version() { + if let Ok(version) = super::version() { + assert!(version.major >= 4); + } else { + println!("Gnuplot not installed."); + } + } + + #[test] + fn test_parse_version_on_valid_string() { + let string = "gnuplot 5.0 patchlevel 7"; + let version = super::parse_version(&string).unwrap(); + assert_eq!(5, version.major); + assert_eq!(0, version.minor); + assert_eq!("7", &version.patch); + } + + #[test] + fn test_parse_gentoo_version() { + let string = "gnuplot 5.2 patchlevel 5a (Gentoo revision r0)"; + let version = super::parse_version(&string).unwrap(); + assert_eq!(5, version.major); + assert_eq!(2, version.minor); + assert_eq!("5a", &version.patch); + } + + #[test] + fn test_parse_version_returns_error_on_invalid_strings() { + let strings = [ + "", + "foobar", + "gnuplot 50 patchlevel 7", + "gnuplot 5.0 patchlevel", + "gnuplot foo.bar patchlevel 7", + ]; + for string in &strings { + assert!(super::parse_version(string).is_err()); + } + } +} diff --git a/vendor/criterion-plot/src/map.rs b/vendor/criterion-plot/src/map.rs new file mode 100755 index 000000000..7099a96bc --- /dev/null +++ b/vendor/criterion-plot/src/map.rs @@ -0,0 +1,168 @@ +//! Enum Maps + +pub mod axis { + use crate::Axis; + + const LENGTH: usize = 4; + + pub struct Items<'a, T> + where + T: 'a, + { + map: &'a Map<T>, + state: Option<Axis>, + } + + impl<'a, T> Iterator for Items<'a, T> { + type Item = (Axis, &'a T); + + fn next(&mut self) -> Option<(Axis, &'a T)> { + while let Some(key) = self.state { + self.state = key.next(); + + if let Some(value) = self.map.get(key) { + return Some((key, value)); + } + } + + None + } + } + + pub struct Map<T>([Option<T>; LENGTH]); + + impl<T> Default for Map<T> { + fn default() -> Self { + Self::new() + } + } + + impl<T> Map<T> { + pub fn new() -> Map<T> { + Map([None, None, None, None]) + } + + pub fn contains_key(&self, key: Axis) -> bool { + self.0[key as usize].is_some() + } + + pub fn get(&self, key: Axis) -> Option<&T> { + self.0[key as usize].as_ref() + } + + pub fn get_mut(&mut self, key: Axis) -> Option<&mut T> { + self.0[key as usize].as_mut() + } + + pub fn insert(&mut self, key: Axis, value: T) -> Option<T> { + let key = key as usize; + let old = self.0[key].take(); + + self.0[key] = Some(value); + + old + } + + pub fn iter(&self) -> Items<T> { + Items { + map: self, + state: Some(Axis::BottomX), + } + } + } + + impl<T> Clone for Map<T> + where + T: Clone, + { + fn clone(&self) -> Map<T> { + Map([ + self.0[0].clone(), + self.0[1].clone(), + self.0[2].clone(), + self.0[3].clone(), + ]) + } + } +} + +pub mod grid { + use crate::Grid; + + const LENGTH: usize = 2; + + pub struct Items<'a, T> + where + T: 'a, + { + map: &'a Map<T>, + state: Option<Grid>, + } + + impl<'a, T> Iterator for Items<'a, T> { + type Item = (Grid, &'a T); + + fn next(&mut self) -> Option<(Grid, &'a T)> { + while let Some(key) = self.state { + self.state = key.next(); + + if let Some(value) = self.map.get(key) { + return Some((key, value)); + } + } + + None + } + } + + pub struct Map<T>([Option<T>; LENGTH]); + + impl<T> Map<T> { + pub fn new() -> Map<T> { + Map([None, None]) + } + + pub fn contains_key(&self, key: Grid) -> bool { + self.0[key as usize].is_some() + } + + pub fn get(&self, key: Grid) -> Option<&T> { + self.0[key as usize].as_ref() + } + + pub fn get_mut(&mut self, key: Grid) -> Option<&mut T> { + self.0[key as usize].as_mut() + } + + pub fn insert(&mut self, key: Grid, value: T) -> Option<T> { + let key = key as usize; + let old = self.0[key].take(); + + self.0[key] = Some(value); + + old + } + + pub fn iter(&self) -> Items<T> { + Items { + map: self, + state: Some(Grid::Major), + } + } + } + + impl<T> Clone for Map<T> + where + T: Clone, + { + fn clone(&self) -> Map<T> { + Map([self.0[0].clone(), self.0[1].clone()]) + } + } + + impl<T> Default for Map<T> { + fn default() -> Self { + Self::new() + } + } +} diff --git a/vendor/criterion-plot/src/prelude.rs b/vendor/criterion-plot/src/prelude.rs new file mode 100755 index 000000000..e42c45f66 --- /dev/null +++ b/vendor/criterion-plot/src/prelude.rs @@ -0,0 +1,13 @@ +//! A collection of the most used traits, structs and enums + +pub use crate::candlestick::Candlesticks; +pub use crate::curve::Curve::{Dots, Impulses, Lines, LinesPoints, Points, Steps}; +pub use crate::errorbar::ErrorBar::{XErrorBars, XErrorLines, YErrorBars, YErrorLines}; +pub use crate::filledcurve::FilledCurve; +pub use crate::key::{Boxed, Horizontal, Justification, Order, Position, Stacked, Vertical}; +pub use crate::proxy::{Font, Label, Output, Title}; +pub use crate::traits::{Configure, Plot, Set}; +pub use crate::{ + Axes, Axis, BoxWidth, Color, Figure, FontSize, Grid, Key, LineType, LineWidth, Opacity, + PointSize, PointType, Range, Scale, ScaleFactor, Size, Terminal, TicLabels, +}; diff --git a/vendor/criterion-plot/src/proxy.rs b/vendor/criterion-plot/src/proxy.rs new file mode 100755 index 000000000..401b7f923 --- /dev/null +++ b/vendor/criterion-plot/src/proxy.rs @@ -0,0 +1,47 @@ +//! Generic constructors for newtypes + +#![allow(non_snake_case)] + +use crate::{Font as FontType, Label as LabelType, Output as OutputType, Title as TitleType}; +use std::borrow::Cow; +use std::path::Path; + +/// Generic constructor for `Font` +#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#[inline(always)] +pub fn Font<S>(string: S) -> FontType +where + S: Into<Cow<'static, str>>, +{ + FontType(string.into()) +} + +/// Generic constructor for `Label` +#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#[inline(always)] +pub fn Label<S>(string: S) -> LabelType +where + S: Into<Cow<'static, str>>, +{ + LabelType(string.into()) +} + +/// Generic constructor for `Title` +#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#[inline(always)] +pub fn Title<S>(string: S) -> TitleType +where + S: Into<Cow<'static, str>>, +{ + TitleType(string.into()) +} + +/// Generic constructor for `Output` +#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#[inline(always)] +pub fn Output<P>(path: P) -> OutputType +where + P: Into<Cow<'static, Path>>, +{ + OutputType(path.into()) +} diff --git a/vendor/criterion-plot/src/traits.rs b/vendor/criterion-plot/src/traits.rs new file mode 100755 index 000000000..52d22332b --- /dev/null +++ b/vendor/criterion-plot/src/traits.rs @@ -0,0 +1,35 @@ +//! Traits + +/// Overloaded `configure` method +pub trait Configure<This> { + /// The properties of what's being configured + type Properties; + + /// Configure some set of properties + fn configure<F>(&mut self, this: This, function: F) -> &mut Self + where + F: FnOnce(&mut Self::Properties) -> &mut Self::Properties; +} + +/// Types that can be plotted +pub trait Data { + /// Convert the type into a double precision float + fn f64(self) -> f64; +} + +/// Overloaded `plot` method +pub trait Plot<This> { + /// The properties associated to the plot + type Properties; + + /// Plots some `data` with some `configuration` + fn plot<F>(&mut self, this: This, function: F) -> &mut Self + where + F: FnOnce(&mut Self::Properties) -> &mut Self::Properties; +} + +/// Overloaded `set` method +pub trait Set<T> { + /// Sets some property + fn set(&mut self, value: T) -> &mut Self; +} |