diff options
Diffstat (limited to 'vendor/criterion-plot')
-rw-r--r-- | vendor/criterion-plot/.cargo-checksum.json | 1 | ||||
-rwxr-xr-x | vendor/criterion-plot/CONTRIBUTING.md | 85 | ||||
-rw-r--r-- | vendor/criterion-plot/Cargo.toml | 56 | ||||
-rwxr-xr-x | vendor/criterion-plot/LICENSE-APACHE | 201 | ||||
-rwxr-xr-x | vendor/criterion-plot/LICENSE-MIT | 25 | ||||
-rwxr-xr-x | vendor/criterion-plot/README.md | 38 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/axis.rs | 201 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/candlestick.rs | 154 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/curve.rs | 273 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/data.rs | 174 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/display.rs | 139 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/errorbar.rs | 293 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/filledcurve.rs | 143 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/grid.rs | 46 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/key.rs | 221 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/lib.rs | 1093 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/map.rs | 168 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/prelude.rs | 13 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/proxy.rs | 47 | ||||
-rwxr-xr-x | vendor/criterion-plot/src/traits.rs | 35 |
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; +} |