summaryrefslogtreecommitdiffstats
path: root/vendor/criterion-plot
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/criterion-plot')
-rw-r--r--vendor/criterion-plot/.cargo-checksum.json1
-rwxr-xr-xvendor/criterion-plot/CONTRIBUTING.md85
-rw-r--r--vendor/criterion-plot/Cargo.toml56
-rwxr-xr-xvendor/criterion-plot/LICENSE-APACHE201
-rwxr-xr-xvendor/criterion-plot/LICENSE-MIT25
-rwxr-xr-xvendor/criterion-plot/README.md38
-rwxr-xr-xvendor/criterion-plot/src/axis.rs201
-rwxr-xr-xvendor/criterion-plot/src/candlestick.rs154
-rwxr-xr-xvendor/criterion-plot/src/curve.rs273
-rwxr-xr-xvendor/criterion-plot/src/data.rs174
-rwxr-xr-xvendor/criterion-plot/src/display.rs139
-rwxr-xr-xvendor/criterion-plot/src/errorbar.rs293
-rwxr-xr-xvendor/criterion-plot/src/filledcurve.rs143
-rwxr-xr-xvendor/criterion-plot/src/grid.rs46
-rwxr-xr-xvendor/criterion-plot/src/key.rs221
-rwxr-xr-xvendor/criterion-plot/src/lib.rs1093
-rwxr-xr-xvendor/criterion-plot/src/map.rs168
-rwxr-xr-xvendor/criterion-plot/src/prelude.rs13
-rwxr-xr-xvendor/criterion-plot/src/proxy.rs47
-rwxr-xr-xvendor/criterion-plot/src/traits.rs35
20 files changed, 3406 insertions, 0 deletions
diff --git a/vendor/criterion-plot/.cargo-checksum.json b/vendor/criterion-plot/.cargo-checksum.json
new file mode 100644
index 000000000..e668854eb
--- /dev/null
+++ b/vendor/criterion-plot/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CONTRIBUTING.md":"7b480a4b278228ff3fe5d3f5915291336d92468382eb1326b54cbff27fec1b83","Cargo.toml":"b53f9f53f0640df0a2beaccda9c133a0b43bf79005042d1defb95c662a9d5051","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4594f18866be94a3ce309ed8f94d92699f5b87739b76e1216addca75f5253fa7","README.md":"4db87647df0bd07d9138e0e5cc7d460b391fd824506bae8180bdfa43f00129d2","src/axis.rs":"4bbbe177b5fde566948eb0dfe1aa0e7f4e7faf62f2bb1e2321215ffa57133675","src/candlestick.rs":"fe45b01bada19567cf63c338873b9d5ea4cf962d7a19d00b25d34b198df5792c","src/curve.rs":"8f00c0279dfe0de5bddf93e623ade0619db50927ba76caa7bc64776b8f186e38","src/data.rs":"847d1b5730f1c83454453fad90ebd95dfc9ed1fb2ef37025ddef6f649d47a4a0","src/display.rs":"c534c1fdfa33e5f2c7eb03884cf82a8f7484083f320231cf1436e6c776f5b064","src/errorbar.rs":"b7fcdbf8160c25bb48ff64ca14364a2612f5936542d20629076f6ac433d3ba9b","src/filledcurve.rs":"f2aec7197576dcc15277e6794321370086cdbe3d465309c496f1fbfefe90d562","src/grid.rs":"72716ed0d701a7a5cedb498fb15380bb2a6d03cb9fd48f6126043c420dbe1621","src/key.rs":"98586d40633bccc4b414d5b4e39f5135b10884e15834ee43ac2b260b7900505e","src/lib.rs":"fd5418733a1f43f0c88db52ae76a59c78da6c417328262d8e2b87afd4e607c90","src/map.rs":"9ecf7cb1e08500e5477125e248c69a72903b2f4fc444e9f9f2faf141a580169c","src/prelude.rs":"40beea28cf50823c32a64d58482deab56386cb0428d62e4c91f57c2292bb2b0b","src/proxy.rs":"341af8e7bba54857222224f49659d3bb3ce366f57ba2d7ca2b1d35abc41129ac","src/traits.rs":"37e629edcd80ec26a50cf33097f18c3b3bccb4e2df30caa1ab69c155338cbb71"},"package":"2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"} \ No newline at end of file
diff --git a/vendor/criterion-plot/CONTRIBUTING.md b/vendor/criterion-plot/CONTRIBUTING.md
new file mode 100755
index 000000000..59ae0262e
--- /dev/null
+++ b/vendor/criterion-plot/CONTRIBUTING.md
@@ -0,0 +1,85 @@
+# Contributing to Criterion.<span></span>rs
+
+## Ideas, Experiences and Questions
+
+The easiest way to contribute to Criterion.<span></span>rs is to use it and report your experiences, ask questions and contribute ideas. We'd love to hear your thoughts on how to make Criterion.<span></span>rs better, or your comments on why you are or are not currently using it.
+
+Issues, ideas, requests and questions should be posted on the issue tracker at:
+
+https://github.com/bheisler/criterion.rs/issues
+
+## A Note on Dependency Updates
+
+Criterion.<span></span>rs does not accept pull requests to update dependencies unless specifically
+requested by the maintaner(s). Dependencies are updated manually by the maintainer(s) before each
+new release.
+
+## Code
+
+Pull requests are welcome, though please raise an issue for discussion first if none exists. We're happy to assist new contributors.
+
+If you're not sure what to work on, try checking the [Beginner label](https://github.com/bheisler/criterion.rs/issues?q=is%3Aissue+is%3Aopen+label%3ABeginner)
+
+To make changes to the code, fork the repo and clone it:
+
+`git clone git@github.com:your-username/criterion.rs.git`
+
+You'll probably want to install [gnuplot](http://www.gnuplot.info/) as well. See the gnuplot website for installation instructions.
+
+Then make your changes to the code. When you're done, run the tests:
+
+```
+cargo test --all
+cargo bench
+```
+
+It's a good idea to run clippy and fix any warnings as well:
+
+```
+rustup component add clippy-preview
+cargo clippy --all
+```
+
+Finally, run Rustfmt to maintain a common code style:
+
+```
+rustup component add rustfmt-preview
+cargo fmt --all
+```
+
+Don't forget to update the CHANGELOG.md file and any appropriate documentation. Once you're finished, push to your fork and submit a pull request. We try to respond to new issues and pull requests quickly, so if there hasn't been any response for more than a few days feel free to ping @bheisler.
+
+Some things that will increase the chance that your pull request is accepted:
+
+* Write tests
+* Clearly document public methods
+* Write a good commit message
+
+## Branches
+
+* PRs with breaking changes are made against the unreleased branch. e.g. branch version-0.4
+* PRs without breaking changes are made against the master branch.
+
+If you're not sure which branch to use just start with master, as this can be changed during review.
+
+When it is time to release the unreleased branch, a PR is made from the unreleased branch to master. e.g. https://github.com/bheisler/criterion.rs/pull/496
+
+## Github Labels
+
+Criterion.<span></span>rs uses a simple set of labels to track issues. Most important are the
+difficulty labels:
+
+* Beginner - Suitable for people new to Criterion.rs, or even new to Rust in general
+* Intermediate - More challenging, likely involves some non-trivial design decisions and/or knowledge
+ of Criterion.<span></span>rs' internals
+* Bigger Project - Large and/or complex project such as designing a complex new feature
+
+Additionally, there are a few other noteworthy labels:
+
+* Breaking Change - Fixing this will have to wait until the next breaking-change release
+* Bug - Something isn't working right
+* Enhancement - Request to add a new feature or otherwise improve Criterion.<span></span>rs in some way
+
+## Code of Conduct
+
+We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html).
diff --git a/vendor/criterion-plot/Cargo.toml b/vendor/criterion-plot/Cargo.toml
new file mode 100644
index 000000000..028ec8df9
--- /dev/null
+++ b/vendor/criterion-plot/Cargo.toml
@@ -0,0 +1,56 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "criterion-plot"
+version = "0.4.5"
+authors = [
+ "Jorge Aparicio <japaricious@gmail.com>",
+ "Brook Heisler <brookheisler@gmail.com>",
+]
+description = "Criterion's plotting library"
+readme = "README.md"
+keywords = [
+ "plotting",
+ "gnuplot",
+ "criterion",
+]
+categories = ["visualization"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/bheisler/criterion.rs"
+
+[dependencies.cast]
+version = "0.3"
+
+[dependencies.itertools]
+version = "0.10"
+
+[dev-dependencies.itertools-num]
+version = "0.1"
+
+[dev-dependencies.num-complex]
+version = "0.4"
+features = ["std"]
+default-features = false
+
+[dev-dependencies.rand]
+version = "0.8"
+
+[badges.appveyor]
+id = "4255ads9ctpupcl2"
+repository = "bheisler/criterion.rs"
+
+[badges.maintenance]
+status = "looking-for-maintainer"
+
+[badges.travis-ci]
+repository = "bheisler/criterion.rs"
diff --git a/vendor/criterion-plot/LICENSE-APACHE b/vendor/criterion-plot/LICENSE-APACHE
new file mode 100755
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/criterion-plot/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/criterion-plot/LICENSE-MIT b/vendor/criterion-plot/LICENSE-MIT
new file mode 100755
index 000000000..ac0fda003
--- /dev/null
+++ b/vendor/criterion-plot/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Jorge Aparicio
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/criterion-plot/README.md b/vendor/criterion-plot/README.md
new file mode 100755
index 000000000..6c403e0af
--- /dev/null
+++ b/vendor/criterion-plot/README.md
@@ -0,0 +1,38 @@
+# `criterion-plot`
+
+> Graphing sub-crate of [Criterion.rs].
+
+This is an unstable implementation detail of [Criterion.rs]. Anything may change
+at any time with no warning, including the public API. For further information,
+see [Criterion.rs].
+
+`criterion-plot` is currently looking for a new maintainer. See
+[this thread](https://users.rust-lang.org/t/call-for-maintainers-criterion-plot/24413) for details.
+
+## License
+
+This project is licensed under either of
+
+* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ ([LICENSE-APACHE](LICENSE-APACHE))
+
+* [MIT License](http://opensource.org/licenses/MIT)
+ ([LICENSE-MIT](LICENSE-MIT))
+
+at your option.
+
+## Contributing
+
+We welcome all people who want to contribute.
+Please see the [contributing instructions] for more information.
+
+Contributions in any form (issues, pull requests, etc.) to this project
+must adhere to Rust's [Code of Conduct].
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+
+[Code of Conduct]: https://www.rust-lang.org/en-US/conduct.html
+[Criterion.rs]: https://github.com/bheisler/criterion.rs
+[contributing instructions]: CONTRIBUTING.md
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;
+}