diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
commit | 9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/error-chain | |
parent | Initial commit. (diff) | |
download | thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/error-chain')
22 files changed, 3525 insertions, 0 deletions
diff --git a/third_party/rust/error-chain/.cargo-checksum.json b/third_party/rust/error-chain/.cargo-checksum.json new file mode 100644 index 0000000000..25299cf4be --- /dev/null +++ b/third_party/rust/error-chain/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"ef6a507058abf31f0e9ca96757e28b02a901ae79e762a3bc7fcf8d1e94fc2d44","Cargo.lock":"f0ff8421e2cf5c319f8201727880716565c3e78ee01c2914f2272cbb6d5f8e32","Cargo.toml":"2a75162596294a04af11f94219ec36c01eee6702027a09918df871fad233e9c7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c43864d39cedab9a1b2aa3d5e480cb58f74cac0b07756670a30c683ce34976a1","README.md":"9fe679f0803f83d65a5b6a26d11305fe042b9ff59494cba31a5904e643240e8e","build.rs":"a1424a03c2df37c5784e8837ce025ad7c2a9efe2e603c80efd3f7ccfbe6b8f07","examples/all.rs":"6f073ea0e3db541a4eefb41436fc03a121a1f932fd6a2798b485a72d64bd1a3c","examples/chain_err.rs":"9a4cfc00808dfde57c97f65969d4ed5a48335b1880c1e2507b71fd9b711bdbae","examples/doc.rs":"426789ff58b2f8792e867d5d85fdb74507cda160285f0130f50d7c4cfff4a51c","examples/has_backtrace.rs":"eedf028ff206938760a53e91d13534b6ad6780b2b6635f405b7896125484a869","examples/quickstart.rs":"80a744c7d309662409b4db255ddcd714e63b2e82a1f0ff00e21525289bbdfe48","examples/size.rs":"d778532f17d9d55e3eb421d920b1cf09b4284d160fffe7c5522258527c8d284c","src/backtrace.rs":"bf70954c483e54fc13f5235efca08f21a02764f34fccdc1a657e66f3632f6f59","src/error_chain.rs":"cb315489643af2b7da7868239b0f1f0e3e6cd3e900030b38617eeddd30e757fc","src/example_generated.rs":"b0742d8df91948a81db01a9b455e0bbe9b211b9c2644a7f10d59f0e099083231","src/impl_error_chain_kind.rs":"ed27688a857e15f4f120769bae892c0280f96e4e082b42ebb2ba1af02f8875ee","src/lib.rs":"cd469e2f18653fc1e6541d82a566a94d8b5769a2e5c6abf3fcdd967eab22246f","src/quick_main.rs":"f77f74104cff1825d9885be1708b5128508312ed5ac92c806fdafa0336f47ead","tests/quick_main.rs":"39a1113cc0d30e5b265e4139cda36f910f8c534a4409e99a9a506a0e88e58f19","tests/tests.rs":"3b80f2c8d45d06dea2ef1375579e63e2fc904ee8c22b1abf285f062b3c1ce271"},"package":"2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"}
\ No newline at end of file diff --git a/third_party/rust/error-chain/CHANGELOG.md b/third_party/rust/error-chain/CHANGELOG.md new file mode 100644 index 0000000000..bd82afc3d5 --- /dev/null +++ b/third_party/rust/error-chain/CHANGELOG.md @@ -0,0 +1,136 @@ +# 0.12.4 +- [executable bits to support build platform linters](https://github.com/rust-lang-nursery/error-chain/pull/289) + +# 0.12.2 +- [allow `Error::description` to be used for rust below 1.42](https://github.com/rust-lang-nursery/error-chain/pull/285) +- [Improvements to has_backtrace_depending_on_env](https://github.com/rust-lang-nursery/error-chain/pull/277) +- Backtrace support now requires rust 1.32.0 + +# 0.12.1 + +- [`std::error::Error::cause` deprecation update](https://github.com/rust-lang-nursery/error-chain/pull/255) +- [Macro invocations use 2018 style](https://github.com/rust-lang-nursery/error-chain/pull/253) + +# 0.12.0 + +- [Remove `impl Deref<Kind> for Error`](https://github.com/rust-lang-nursery/error-chain/pull/192) +- [Fix warning](https://github.com/rust-lang-nursery/error-chain/pull/247) + +# 0.11.0 + +- Change last rust version supported to 1.14 +- [Cache whether RUST_BACKTRACE is enabled in a relaxed atomic static.](https://github.com/rust-lang-nursery/error-chain/pull/210) +- [Mask the `quick_error` macro from the doc](https://github.com/rust-lang-nursery/error-chain/pull/210) +- [Make generated `ErrorKind` enums non-exhaustive](https://github.com/rust-lang-nursery/error-chain/pull/193) +- All 0.11.0-rc.2 changes + +# 0.11.0-rc.2 + +- [Make `ErrorChainIter`'s field private](https://github.com/rust-lang-nursery/error-chain/issues/178) +- [Rename `ErrorChainIter` to `Iter`](https://github.com/rust-lang-nursery/error-chain/issues/168) +- [Implement `Debug` for `ErrorChainIter`](https://github.com/rust-lang-nursery/error-chain/issues/169) +- [Rename `ChainedError::display` to `display_chain`](https://github.com/rust-lang-nursery/error-chain/issues/180) +- [Add a new method for `Error`: `chain_err`.](https://github.com/rust-lang-nursery/error-chain/pull/141) +- [Allow `chain_err` to be used on `Option<T>`](https://github.com/rust-lang-nursery/error-chain/pull/156) +- [Add support for creating an error chain on boxed trait errors (`Box<Error>`)](https://github.com/rust-lang-nursery/error-chain/pull/156) +- [Remove lint for unused doc comment.](https://github.com/rust-lang-nursery/error-chain/pull/199) +- [Hide error_chain_processed macro from documentation.](https://github.com/rust-lang-nursery/error-chain/pull/212) + +# 0.10.0 + +- [Add a new constructor for `Error`: `with_chain`.](https://github.com/rust-lang-nursery/error-chain/pull/126) +- [Add the `ensure!` macro.](https://github.com/rust-lang-nursery/error-chain/pull/135) + +# 0.9.0 + +- Revert [Add a `Sync` bound to errors](https://github.com/rust-lang-nursery/error-chain/pull/110) + +# 0.8.1 + +- Add crates.io category. + +# 0.8.0 + +- [Add a `Sync` bound to errors](https://github.com/rust-lang-nursery/error-chain/pull/110) +- [Add `ChainedError::display` to format error chains](https://github.com/rust-lang-nursery/error-chain/pull/113) + +# 0.7.2 + +- Add `quick_main!` (#88). +- `allow(unused)` for the `Result` wrapper. +- Minimum rust version supported is now 1.10 on some conditions (#103). + +# 0.7.1 + +- [Add the `bail!` macro](https://github.com/rust-lang-nursery/error-chain/pull/76) + +# 0.7.0 + +- [Rollback several design changes to fix regressions](https://github.com/rust-lang-nursery/error-chain/pull/75) +- New `Variant(Error) #[attrs]` for `links` and `foreign_links`. +- Hide implementation details from the doc. +- Always generate `Error::backtrace`. + +# 0.6.2 + +- Allow dead code. + +# 0.6.1 + +- Fix wrong trait constraint in ResultExt implementation (#66). + +# 0.6.0 + +- Conditional compilation for error variants. +- Backtrace generation is now a feature. +- More standard trait implementations for extra convenience. +- Remove ChainErr. +- Remove need to specify `ErrorKind` in `links {}`. +- Add ResultExt trait. +- Error.1 is a struct instead of a tuple. +- Error is now a struct. +- The declarations order is more flexible. +- Way better error reporting when there is a syntax error in the macro call. +- `Result` generation can be disabled. +- At most one declaration of each type can be present. + +# 0.5.0 + +- [Only generate backtraces with RUST_BACKTRACE set](https://github.com/rust-lang-nursery/error-chain/pull/27) +- [Fixup matching, disallow repeating "types" section](https://github.com/rust-lang-nursery/error-chain/pull/26) +- [Fix tests on stable/beta](https://github.com/rust-lang-nursery/error-chain/pull/28) +- [Only deploy docs when tagged](https://github.com/rust-lang-nursery/error-chain/pull/30) + +Contributors: benaryorg, Brian Anderson, Georg Brandl + +# 0.4.2 + +- [Fix the resolution of the ErrorKind description method](https://github.com/rust-lang-nursery/error-chain/pull/24) + +Contributors: Brian Anderson + +# 0.4.1 (yanked) + +- [Fix a problem with resolving methods of the standard Error type](https://github.com/rust-lang-nursery/error-chain/pull/22) + +Contributors: Brian Anderson + +# 0.4.0 (yanked) + +- [Remove the foreign link description and forward to the foreign error](https://github.com/rust-lang-nursery/error-chain/pull/19) +- [Allow missing sections](https://github.com/rust-lang-nursery/error-chain/pull/17) + +Contributors: Brian Anderson, Taylor Cramer + +# 0.3.0 + +- [Forward Display implementation for foreign errors](https://github.com/rust-lang-nursery/error-chain/pull/13) + +Contributors: Brian Anderson, Taylor Cramer + +# 0.2.2 + +- [Don't require `types` section in macro invocation](https://github.com/rust-lang-nursery/error-chain/pull/8) +- [Add "quick start" to README](https://github.com/rust-lang-nursery/error-chain/pull/9) + +Contributors: Brian Anderson, Jake Shadle, Nate Mara diff --git a/third_party/rust/error-chain/Cargo.lock b/third_party/rust/error-chain/Cargo.lock new file mode 100644 index 0000000000..9453307464 --- /dev/null +++ b/third_party/rust/error-chain/Cargo.lock @@ -0,0 +1,67 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" +dependencies = [ + "gimli", +] + +[[package]] +name = "backtrace" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "object", + "rustc-demangle", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "error-chain" +version = "0.12.4" +dependencies = [ + "backtrace", + "version_check", +] + +[[package]] +name = "gimli" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "object" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" diff --git a/third_party/rust/error-chain/Cargo.toml b/third_party/rust/error-chain/Cargo.toml new file mode 100644 index 0000000000..55ed9ac659 --- /dev/null +++ b/third_party/rust/error-chain/Cargo.toml @@ -0,0 +1,32 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "error-chain" +version = "0.12.4" +authors = ["Brian Anderson <banderson@mozilla.com>", "Paul Colomiets <paul@colomiets.name>", "Colin Kiegel <kiegel@gmx.de>", "Yamakaky <yamakaky@yamaworld.fr>", "Andrew Gauger <andygauge@gmail.com>"] +description = "Yet another error boilerplate library." +documentation = "https://docs.rs/error-chain" +readme = "README.md" +keywords = ["error"] +categories = ["rust-patterns"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/error-chain" +[dependencies.backtrace] +version = "0.3.3" +optional = true +[build-dependencies.version_check] +version = "0.9" + +[features] +default = ["backtrace", "example_generated"] +example_generated = [] diff --git a/third_party/rust/error-chain/LICENSE-APACHE b/third_party/rust/error-chain/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/error-chain/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/third_party/rust/error-chain/LICENSE-MIT b/third_party/rust/error-chain/LICENSE-MIT new file mode 100644 index 0000000000..5f28864c84 --- /dev/null +++ b/third_party/rust/error-chain/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2017 The Error-Chain Project Developers + +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/third_party/rust/error-chain/README.md b/third_party/rust/error-chain/README.md new file mode 100644 index 0000000000..b87224d18d --- /dev/null +++ b/third_party/rust/error-chain/README.md @@ -0,0 +1,36 @@ +# error-chain - Consistent error handling for Rust + +[![Build Status](https://travis-ci.com/rust-lang-nursery/error-chain.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/error-chain) +[![Latest Version](https://img.shields.io/crates/v/error-chain.svg)](https://crates.io/crates/error-chain) +[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-green.svg)](https://github.com/rust-lang-nursery/error-chain) + +`error-chain` makes it easy to take full advantage of Rust's error +handling features without the overhead of maintaining boilerplate +error types and conversions. It implements an opinionated strategy for +defining your own error types, as well as conversions from others' +error types. + +[Documentation (crates.io)](https://docs.rs/error-chain). + +[Documentation (master)](https://rust-lang-nursery.github.io/error-chain). + +## Quick start + +If you just want to set up your new project with error-chain, +follow the [quickstart.rs] template, and read this [intro] +to error-chain. + +[quickstart.rs]: https://github.com/rust-lang-nursery/error-chain/blob/master/examples/quickstart.rs +[intro]: http://brson.github.io/2016/11/30/starting-with-error-chain + +## Supported Rust version + +Please view the beginning of the [Travis configuration file](.travis.yml) +to see the oldest supported Rust version. + +Note that `error-chain` supports older versions of Rust when built with +`default-features = false`. + +## License + +MIT/Apache-2.0 diff --git a/third_party/rust/error-chain/build.rs b/third_party/rust/error-chain/build.rs new file mode 100644 index 0000000000..612f2091de --- /dev/null +++ b/third_party/rust/error-chain/build.rs @@ -0,0 +1,21 @@ +extern crate version_check; + +use std::env; +use version_check::is_min_version; + +fn main() { + // Switch on for versions that have Error::source + // As introduced by https://github.com/rust-lang/rust/pull/53533 + if is_min_version("1.30").unwrap_or(false) { + println!("cargo:rustc-cfg=has_error_source"); + } + + if is_min_version("1.42").unwrap_or(false) { + println!("cargo:rustc-cfg=has_error_description_deprecated"); + } + + // So we can get the build profile for has_backtrace_depending_on_env test + if let Ok(profile) = env::var("PROFILE") { + println!("cargo:rustc-cfg=build={:?}", profile); + } +} diff --git a/third_party/rust/error-chain/examples/all.rs b/third_party/rust/error-chain/examples/all.rs new file mode 100644 index 0000000000..840ca95e27 --- /dev/null +++ b/third_party/rust/error-chain/examples/all.rs @@ -0,0 +1,36 @@ +#[macro_use] +extern crate error_chain; + +pub mod inner { + error_chain! {} +} + +#[cfg(feature = "a_feature")] +pub mod feature { + error_chain! {} +} + +error_chain! { + // Types generated by the macro. If empty or absent, it defaults to + // Error, ErrorKind, Result; + types { + // With custom names: + MyError, MyErrorKind, MyResult; + // Without the `Result` wrapper: + // Error, ErrorKind; + } + + // Automatic bindings to other error types generated by `error_chain!`. + links { + Inner(inner::Error, inner::ErrorKind); + // Attributes can be added at the end of the declaration. + Feature(feature::Error, feature::ErrorKind) #[cfg(feature = "a_feature")]; + } + + // Bindings to types implementing std::error::Error. + foreign_links { + Io(::std::io::Error); + } +} + +fn main() {} diff --git a/third_party/rust/error-chain/examples/chain_err.rs b/third_party/rust/error-chain/examples/chain_err.rs new file mode 100644 index 0000000000..c70a25dd60 --- /dev/null +++ b/third_party/rust/error-chain/examples/chain_err.rs @@ -0,0 +1,67 @@ +//! Demonstrates usage of `Error::caused` method. This method enables chaining errors +//! like `ResultExt::chain_err` but doesn't require the presence of a `Result` wrapper. + +#[macro_use] +extern crate error_chain; + +use std::fs::File; + +mod errors { + use super::LaunchStage; + use std::io; + + error_chain! { + foreign_links { + Io(io::Error) #[doc = "Error during IO"]; + } + + errors { + Launch(phase: LaunchStage) { + description("An error occurred during startup") + display("Startup aborted: {:?} did not complete successfully", phase) + } + + ConfigLoad(path: String) { + description("Config file not found") + display("Unable to read file `{}`", path) + } + } + } + + impl From<LaunchStage> for ErrorKind { + fn from(v: LaunchStage) -> Self { + ErrorKind::Launch(v) + } + } +} + +pub use errors::*; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum LaunchStage { + ConfigLoad, + ConfigParse, + ConfigResolve, +} + +/// Read the service config from the file specified. +fn load_config(rel_path: &str) -> Result<()> { + File::open(rel_path) + .map(|_| ()) + .chain_err(|| ErrorKind::ConfigLoad(rel_path.to_string())) +} + +/// Launch the service. +fn launch(rel_path: &str) -> Result<()> { + load_config(rel_path).map_err(|e| match e { + e @ Error(ErrorKind::ConfigLoad(_), _) => e.chain_err(|| LaunchStage::ConfigLoad), + e => e.chain_err(|| "Unknown failure"), + }) +} + +fn main() { + let chain = launch("does_not_exist.json").unwrap_err(); + for err in chain.iter() { + println!("{}", err); + } +} diff --git a/third_party/rust/error-chain/examples/doc.rs b/third_party/rust/error-chain/examples/doc.rs new file mode 100644 index 0000000000..68f57d7884 --- /dev/null +++ b/third_party/rust/error-chain/examples/doc.rs @@ -0,0 +1,28 @@ +#![deny(missing_docs)] + +//! This module is used to check that all generated items are documented. + +#[macro_use] +extern crate error_chain; + +/// Inner module. +pub mod inner { + error_chain! {} +} + +error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Io"]; + } + errors { + /// Doc + Test2 { + + } + } +} + +fn main() {} diff --git a/third_party/rust/error-chain/examples/has_backtrace.rs b/third_party/rust/error-chain/examples/has_backtrace.rs new file mode 100644 index 0000000000..c5dac058a8 --- /dev/null +++ b/third_party/rust/error-chain/examples/has_backtrace.rs @@ -0,0 +1,18 @@ +//! Exits with exit code 0 if backtraces are disabled and 1 if they are enabled. +//! Used by tests to make sure backtraces are available when they should be. Should not be used +//! outside of the tests. + +#[macro_use] +extern crate error_chain; + +error_chain! { + errors { + MyError + } +} + +fn main() { + let err = Error::from(ErrorKind::MyError); + let has_backtrace = err.backtrace().is_some(); + ::std::process::exit(has_backtrace as i32); +} diff --git a/third_party/rust/error-chain/examples/quickstart.rs b/third_party/rust/error-chain/examples/quickstart.rs new file mode 100644 index 0000000000..e410a62b8a --- /dev/null +++ b/third_party/rust/error-chain/examples/quickstart.rs @@ -0,0 +1,78 @@ +// Simple and robust error handling with error-chain! +// Use this as a template for new projects. + +// `error_chain!` can recurse deeply +#![recursion_limit = "1024"] + +// Import the macro. Don't forget to add `error-chain` in your +// `Cargo.toml`! +#[macro_use] +extern crate error_chain; + +// We'll put our errors in an `errors` module, and other modules in +// this crate will `use errors::*;` to get access to everything +// `error_chain!` creates. +mod errors { + // Create the Error, ErrorKind, ResultExt, and Result types + error_chain! {} +} + +// This only gives access within this module. Make this `pub use errors::*;` +// instead if the types must be accessible from other modules (e.g., within +// a `links` section). +use errors::*; + +fn main() { + if let Err(ref e) = run() { + use std::io::Write; + let stderr = &mut ::std::io::stderr(); + let errmsg = "Error writing to stderr"; + + writeln!(stderr, "error: {}", e).expect(errmsg); + + for e in e.iter().skip(1) { + writeln!(stderr, "caused by: {}", e).expect(errmsg); + } + + // The backtrace is not always generated. Try to run this example + // with `RUST_BACKTRACE=1`. + if let Some(backtrace) = e.backtrace() { + writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg); + } + + ::std::process::exit(1); + } +} + +// The above main gives you maximum control over how the error is +// formatted. If you don't care (i.e. you want to display the full +// error during an assert) you can just call the `display_chain` method +// on the error object +#[allow(dead_code)] +fn alternative_main() { + if let Err(ref e) = run() { + use error_chain::ChainedError; + use std::io::Write; // trait which holds `display_chain` + let stderr = &mut ::std::io::stderr(); + let errmsg = "Error writing to stderr"; + + writeln!(stderr, "{}", e.display_chain()).expect(errmsg); + ::std::process::exit(1); + } +} + +// Use this macro to auto-generate the main above. You may want to +// set the `RUST_BACKTRACE` env variable to see a backtrace. +// quick_main!(run); + +// Most functions will return the `Result` type, imported from the +// `errors` module. It is a typedef of the standard `Result` type +// for which the error type is always our own `Error`. +fn run() -> Result<()> { + use std::fs::File; + + // This operation will fail + File::open("tretrete").chain_err(|| "unable to open tretrete file")?; + + Ok(()) +} diff --git a/third_party/rust/error-chain/examples/size.rs b/third_party/rust/error-chain/examples/size.rs new file mode 100644 index 0000000000..3e180684e8 --- /dev/null +++ b/third_party/rust/error-chain/examples/size.rs @@ -0,0 +1,30 @@ +#[macro_use] +extern crate error_chain; + +use std::mem::{size_of, size_of_val}; + +error_chain! { + errors { + AVariant + Another + } +} + +fn main() { + println!("Memory usage in bytes"); + println!("---------------------"); + println!("Result<()>: {}", size_of::<Result<()>>()); + println!(" (): {}", size_of::<()>()); + println!(" Error: {}", size_of::<Error>()); + println!(" ErrorKind: {}", size_of::<ErrorKind>()); + let msg = ErrorKind::Msg("test".into()); + println!(" ErrorKind::Msg: {}", size_of_val(&msg)); + println!(" String: {}", size_of::<String>()); + println!(" State: {}", size_of::<error_chain::State>()); + let state = error_chain::State { + next_error: None, + backtrace: error_chain::InternalBacktrace::new(), + }; + println!(" State.next_error: {}", size_of_val(&state.next_error)); + println!(" State.backtrace: {}", size_of_val(&state.backtrace)); +} diff --git a/third_party/rust/error-chain/src/backtrace.rs b/third_party/rust/error-chain/src/backtrace.rs new file mode 100644 index 0000000000..14be75ce1b --- /dev/null +++ b/third_party/rust/error-chain/src/backtrace.rs @@ -0,0 +1,111 @@ +pub use self::imp::{Backtrace, InternalBacktrace}; + +#[cfg(feature = "backtrace")] +mod imp { + extern crate backtrace; + + use std::cell::UnsafeCell; + use std::env; + use std::fmt; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::{Arc, Mutex}; + + /// Internal representation of a backtrace + #[doc(hidden)] + #[derive(Clone)] + pub struct InternalBacktrace { + backtrace: Option<Arc<MaybeResolved>>, + } + + struct MaybeResolved { + resolved: Mutex<bool>, + backtrace: UnsafeCell<Backtrace>, + } + + unsafe impl Send for MaybeResolved {} + unsafe impl Sync for MaybeResolved {} + + pub use self::backtrace::Backtrace; + + impl InternalBacktrace { + /// Returns a backtrace of the current call stack if `RUST_BACKTRACE` + /// is set to anything but ``0``, and `None` otherwise. This is used + /// in the generated error implementations. + #[doc(hidden)] + pub fn new() -> InternalBacktrace { + static ENABLED: AtomicUsize = AtomicUsize::new(0); + + match ENABLED.load(Ordering::SeqCst) { + 0 => { + let enabled = match env::var_os("RUST_BACKTRACE") { + Some(ref val) if val != "0" => true, + _ => false, + }; + ENABLED.store(enabled as usize + 1, Ordering::SeqCst); + if !enabled { + return InternalBacktrace { backtrace: None }; + } + } + 1 => return InternalBacktrace { backtrace: None }, + _ => {} + } + + InternalBacktrace { + backtrace: Some(Arc::new(MaybeResolved { + resolved: Mutex::new(false), + backtrace: UnsafeCell::new(Backtrace::new_unresolved()), + })), + } + } + + /// Acquire the internal backtrace + #[doc(hidden)] + pub fn as_backtrace(&self) -> Option<&Backtrace> { + let bt = match self.backtrace { + Some(ref bt) => bt, + None => return None, + }; + let mut resolved = bt.resolved.lock().unwrap(); + unsafe { + if !*resolved { + (*bt.backtrace.get()).resolve(); + *resolved = true; + } + Some(&*bt.backtrace.get()) + } + } + } + + impl fmt::Debug for InternalBacktrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InternalBacktrace") + .field("backtrace", &self.as_backtrace()) + .finish() + } + } +} + +#[cfg(not(feature = "backtrace"))] +mod imp { + /// Dummy type used when the `backtrace` feature is disabled. + pub type Backtrace = (); + + /// Internal representation of a backtrace + #[doc(hidden)] + #[derive(Clone, Debug)] + pub struct InternalBacktrace {} + + impl InternalBacktrace { + /// Returns a new backtrace + #[doc(hidden)] + pub fn new() -> InternalBacktrace { + InternalBacktrace {} + } + + /// Returns the internal backtrace + #[doc(hidden)] + pub fn as_backtrace(&self) -> Option<&Backtrace> { + None + } + } +} diff --git a/third_party/rust/error-chain/src/error_chain.rs b/third_party/rust/error-chain/src/error_chain.rs new file mode 100644 index 0000000000..8382709621 --- /dev/null +++ b/third_party/rust/error-chain/src/error_chain.rs @@ -0,0 +1,564 @@ +#[doc(hidden)] +#[macro_export] +#[cfg(not(has_error_source))] +macro_rules! impl_error_chain_cause_or_source { + ( + types { + $error_kind_name:ident + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + ) => { + #[allow(unknown_lints, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn cause(&self) -> Option<&::std::error::Error> { + match self.1.next_error { + Some(ref c) => Some(&**c), + None => { + match self.0 { + $( + $(#[$meta_foreign_links])* + $error_kind_name::$foreign_link_variant(ref foreign_err) => { + foreign_err.cause() + } + ) * + _ => None + } + } + } + } + }; +} + +#[cfg(has_error_source)] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_error_chain_cause_or_source { + ( + types { + $error_kind_name:ident + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + ) => { + #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn source(&self) -> Option<&(std::error::Error + 'static)> { + match self.1.next_error { + Some(ref c) => Some(&**c), + None => { + match self.0 { + $( + $(#[$meta_foreign_links])* + $error_kind_name::$foreign_link_variant(ref foreign_err) => { + foreign_err.source() + } + ) * + _ => None + } + } + } + } + }; +} + +/// Conditional usage of deprecated Error::description +#[doc(hidden)] +#[cfg(has_error_description_deprecated)] +#[macro_export(local_inner_macros)] +macro_rules! call_to_deprecated_description { + ($e:ident) => { + "" + }; +} + +#[doc(hidden)] +#[cfg(not(has_error_description_deprecated))] +#[macro_export(local_inner_macros)] +macro_rules! call_to_deprecated_description { + ($e:ident) => { + ::std::error::Error::description($e) + }; +} + +/// Prefer to use `error_chain` instead of this macro. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_error_chain_processed { + // Default values for `types`. + ( + types {} + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + Error, ErrorKind, ResultExt, Result; + } + $( $rest )* + } + }; + // With `Result` wrapper. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident, $result_name:ident; + } + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + $error_name, $error_kind_name, + $result_ext_name; + } + $( $rest )* + } + /// Convenient wrapper around `std::Result`. + #[allow(unused)] + pub type $result_name<T> = ::std::result::Result<T, $error_name>; + }; + + // With `Msg` variant. + ( + types { + $error_name:ident, $error_kind_name:ident, $($types:tt)* + } + links $links:tt + foreign_links $foreign_links:tt + errors { $($errors:tt)* } + ) => { + impl_error_chain_processed! { + types { + $error_name, $error_kind_name, $($types)* + } + skip_msg_variant + links $links + foreign_links $foreign_links + errors { + /// A convenient variant for String. + Msg(s: String) { + description(&s) + display("{}", s) + } + + $($errors)* + } + } + + impl<'a> From<&'a str> for $error_kind_name { + fn from(s: &'a str) -> Self { + $error_kind_name::Msg(s.into()) + } + } + + impl From<String> for $error_kind_name { + fn from(s: String) -> Self { + $error_kind_name::Msg(s) + } + } + + impl<'a> From<&'a str> for $error_name { + fn from(s: &'a str) -> Self { + Self::from_kind(s.into()) + } + } + + impl From<String> for $error_name { + fn from(s: String) -> Self { + Self::from_kind(s.into()) + } + } + }; + + // Without `Result` wrapper or `Msg` variant. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident; + } + + skip_msg_variant + + links { + $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) + $( #[$meta_links:meta] )*; ) * + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + + errors { + $( $error_chunks:tt ) * + } + + ) => { + /// The Error type. + /// + /// This tuple struct is made of two elements: + /// + /// - an `ErrorKind` which is used to determine the type of the error. + /// - An internal `State`, not meant for direct use outside of `error_chain` + /// internals, containing: + /// - a backtrace, generated when the error is created. + /// - an error chain, used for the implementation of `Error::cause()`. + #[derive(Debug)] + pub struct $error_name( + // The members must be `pub` for `links`. + /// The kind of the error. + pub $error_kind_name, + /// Contains the error chain and the backtrace. + #[doc(hidden)] + pub $crate::State, + ); + + impl $crate::ChainedError for $error_name { + type ErrorKind = $error_kind_name; + + fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { + $error_name(kind, state) + } + + fn from_kind(kind: Self::ErrorKind) -> Self { + Self::from_kind(kind) + } + + fn with_chain<E, K>(error: E, kind: K) + -> Self + where E: ::std::error::Error + Send + 'static, + K: Into<Self::ErrorKind> + { + Self::with_chain(error, kind) + } + + fn kind(&self) -> &Self::ErrorKind { + self.kind() + } + + fn iter(&self) -> $crate::Iter { + $crate::Iter::new(Some(self)) + } + + fn chain_err<F, EK>(self, error: F) -> Self + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.chain_err(error) + } + + fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.backtrace() + } + + impl_extract_backtrace!($error_name + $error_kind_name + $([$link_error_path, $(#[$meta_links])*])*); + } + + #[allow(dead_code)] + impl $error_name { + /// Constructs an error from a kind, and generates a backtrace. + pub fn from_kind(kind: $error_kind_name) -> $error_name { + $error_name( + kind, + $crate::State::default(), + ) + } + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + pub fn with_chain<E, K>(error: E, kind: K) + -> $error_name + where E: ::std::error::Error + Send + 'static, + K: Into<$error_kind_name> + { + $error_name::with_boxed_chain(Box::new(error), kind) + } + + /// Construct a chained error from another boxed error and a kind, and generates a backtrace + #[allow(unknown_lints, bare_trait_objects)] + pub fn with_boxed_chain<K>(error: Box<::std::error::Error + Send>, kind: K) + -> $error_name + where K: Into<$error_kind_name> + { + $error_name( + kind.into(), + $crate::State::new::<$error_name>(error, ), + ) + } + + /// Returns the kind of the error. + pub fn kind(&self) -> &$error_kind_name { + &self.0 + } + + /// Iterates over the error chain. + pub fn iter(&self) -> $crate::Iter { + $crate::ChainedError::iter(self) + } + + /// Returns the backtrace associated with this error. + pub fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.1.backtrace() + } + + /// Extends the error chain with a new entry. + pub fn chain_err<F, EK>(self, error: F) -> $error_name + where F: FnOnce() -> EK, EK: Into<$error_kind_name> { + $error_name::with_chain(self, Self::from_kind(error().into())) + } + + /// A short description of the error. + /// This method is identical to [`Error::description()`](https://doc.rust-lang.org/nightly/std/error/trait.Error.html#tymethod.description) + pub fn description(&self) -> &str { + self.0.description() + } + } + + impl ::std::error::Error for $error_name { + #[cfg(not(has_error_description_deprecated))] + fn description(&self) -> &str { + self.description() + } + + impl_error_chain_cause_or_source!{ + types { + $error_kind_name + } + foreign_links { + $( $foreign_link_variant ( $foreign_link_error_path ) + $( #[$meta_foreign_links] )*; )* + } + } + } + + impl ::std::fmt::Display for $error_name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(&self.0, f) + } + } + + $( + $(#[$meta_links])* + impl From<$link_error_path> for $error_name { + fn from(e: $link_error_path) -> Self { + $error_name( + $error_kind_name::$link_variant(e.0), + e.1, + ) + } + } + ) * + + $( + $(#[$meta_foreign_links])* + impl From<$foreign_link_error_path> for $error_name { + fn from(e: $foreign_link_error_path) -> Self { + $error_name::from_kind( + $error_kind_name::$foreign_link_variant(e) + ) + } + } + ) * + + impl From<$error_kind_name> for $error_name { + fn from(e: $error_kind_name) -> Self { + $error_name::from_kind(e) + } + } + + // The ErrorKind type + // -------------- + + impl_error_chain_kind! { + /// The kind of an error. + #[derive(Debug)] + pub enum $error_kind_name { + $( + $(#[$meta_links])* + $link_variant(e: $link_kind_path) { + description(e.description()) + display("{}", e) + } + ) * + + $( + $(#[$meta_foreign_links])* + $foreign_link_variant(err: $foreign_link_error_path) { + description(call_to_deprecated_description!(err)) + display("{}", err) + } + ) * + + $($error_chunks)* + } + } + + $( + $(#[$meta_links])* + impl From<$link_kind_path> for $error_kind_name { + fn from(e: $link_kind_path) -> Self { + $error_kind_name::$link_variant(e) + } + } + ) * + + impl From<$error_name> for $error_kind_name { + fn from(e: $error_name) -> Self { + e.0 + } + } + + // The ResultExt trait defines the `chain_err` method. + + /// Additional methods for `Result`, for easy interaction with this crate. + pub trait $result_ext_name<T> { + /// If the `Result` is an `Err` then `chain_err` evaluates the closure, + /// which returns *some type that can be converted to `ErrorKind`*, boxes + /// the original error to store as the cause, then returns a new error + /// containing the original error. + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name>; + } + + impl<T, E> $result_ext_name<T> for ::std::result::Result<T, E> where E: ::std::error::Error + Send + 'static { + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.map_err(move |e| { + let state = $crate::State::new::<$error_name>(Box::new(e), ); + $crate::ChainedError::new(callback().into(), state) + }) + } + } + + impl<T> $result_ext_name<T> for ::std::option::Option<T> { + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.ok_or_else(move || { + $crate::ChainedError::from_kind(callback().into()) + }) + } + } + + + }; +} + +/// Internal macro used for reordering of the fields. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! error_chain_processing { + ( + ({}, $($rest:tt)*) + types $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, {}, $($rest:tt)*) + links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, {}, $($rest:tt)*) + foreign_links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, $c:tt, {}, $($rest:tt)*) + errors $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $c, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, $c:tt, $d:tt, {}, $($rest:tt)*) + skip_msg_variant + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $c, $d, {skip_msg_variant}, $($rest)*) + $($tail)* + } + }; + + ( ($a:tt, $b:tt, $c:tt, $d:tt, {$($e:tt)*},) ) => { + impl_error_chain_processed! { + types $a + $($e)* + links $b + foreign_links $c + errors $d + } + }; +} + +/// Macro for generating error types and traits. See crate level documentation for details. +#[macro_export(local_inner_macros)] +macro_rules! error_chain { + ( $($args:tt)* ) => { + error_chain_processing! { + ({}, {}, {}, {}, {},) + $($args)* + } + }; +} + +/// Macro used to manage the `backtrace` feature. +/// +/// See +/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3 +/// for more details. +#[macro_export] +#[doc(hidden)] +macro_rules! impl_extract_backtrace { + ($error_name: ident + $error_kind_name: ident + $([$link_error_path: path, $(#[$meta_links: meta])*])*) => { + #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn extract_backtrace(e: &(::std::error::Error + Send + 'static)) + -> Option<$crate::InternalBacktrace> { + if let Some(e) = e.downcast_ref::<$error_name>() { + return Some(e.1.backtrace.clone()); + } + $( + $( #[$meta_links] )* + { + if let Some(e) = e.downcast_ref::<$link_error_path>() { + return Some(e.1.backtrace.clone()); + } + } + ) * + None + } + } +} diff --git a/third_party/rust/error-chain/src/example_generated.rs b/third_party/rust/error-chain/src/example_generated.rs new file mode 100644 index 0000000000..c0f4d23014 --- /dev/null +++ b/third_party/rust/error-chain/src/example_generated.rs @@ -0,0 +1,38 @@ +//! These modules show an example of code generated by the macro. **IT MUST NOT BE +//! USED OUTSIDE THIS CRATE**. +//! +//! This is the basic error structure. You can see that `ErrorKind` +//! has been populated in a variety of ways. All `ErrorKind`s get a +//! `Msg` variant for basic errors. When strings are converted to +//! `ErrorKind`s they become `ErrorKind::Msg`. The "links" defined in +//! the macro are expanded to the `Inner` variant, and the +//! "foreign links" to the `Io` variant. +//! +//! Both types come with a variety of `From` conversions as well: +//! `Error` can be created from `ErrorKind`, `&str` and `String`, +//! and the `links` and `foreign_links` error types. `ErrorKind` +//! can be created from the corresponding `ErrorKind`s of the link +//! types, as well as from `&str` and `String`. +//! +//! `into()` and `From::from` are used heavily to massage types into +//! the right shape. Which one to use in any specific case depends on +//! the influence of type inference, but there are some patterns that +//! arise frequently. + +/// Another code generated by the macro. +pub mod inner { + error_chain! {} +} + +error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Link to a `std::io::Error` type."]; + } + errors { + #[doc = "A custom error kind."] + Custom + } +} diff --git a/third_party/rust/error-chain/src/impl_error_chain_kind.rs b/third_party/rust/error-chain/src/impl_error_chain_kind.rs new file mode 100644 index 0000000000..4acf8435b2 --- /dev/null +++ b/third_party/rust/error-chain/src/impl_error_chain_kind.rs @@ -0,0 +1,383 @@ +/// From https://github.com/tailhook/quick-error +/// Changes: +/// - replace `impl Error` by `impl Item::description` +/// - $imeta + +/// Because of the `#[macro_export(local_inner_macros)]` usage on `impl_error_chain_kind` that macro +/// will only look inside this crate for macros to invoke. So using `stringify` or `write` from +/// the standard library will fail. Thus we here create simple wrappers for them that are not +/// exported as `local_inner_macros`, and thus they can in turn use the standard library macros. +#[macro_export] +macro_rules! stringify_internal { + ($($t:tt)*) => { stringify!($($t)*) } +} + +/// Macro used interally for output expanding an expression +#[macro_export] +macro_rules! write_internal { + ($dst:expr, $($arg:tt)*) => (write!($dst, $($arg)*)) +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! impl_error_chain_kind { + ( $(#[$meta:meta])* + pub enum $name:ident { $($chunks:tt)* } + ) => { + impl_error_chain_kind!(SORT [pub enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + // Queue is empty, can do the work + (SORT [pub enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + impl_error_chain_kind!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + // Add meta to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add ident to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$(#[$bmeta])* => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on meta after ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + enum [$(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] + items [$($( #[$imeta:meta] )* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add tuple enum-variant + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*] + ); + }; + // Add struct enum-variant - e.g. { descr: &'static str } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*]); + }; + // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*]); + }; + // Add braces and flush always on braces + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ {$( $qfuncs:tt )*} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ] + buf [ ] + queue [$( $tail )*]); + }; + // Flush buffer on double ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on end + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ ] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ ] + queue [ ]); + }; + // Public enum (Queue Empty) + (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + pub enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*, + )* + + #[doc(hidden)] + __Nonexhaustive {} + } + }; + // Unit variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: UNIT [ ] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {} ] + queue [ $($queue)* ] + ); + }; + // Tuple variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem (($( $qtyp ),+)) {} ] + queue [ $($queue)* ] + ); + }; + // Struct variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ] + queue [ $($queue)* ] + ); + }; + (IMPLEMENTATIONS + $name:ident {$( + $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} + )*} + ) => { + #[allow(unknown_lints, unused, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result + { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + let display_fn = impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $funcs )*}); + + display_fn(self, fmt) + } + )* + + _ => Ok(()) + } + } + } + #[allow(unknown_lints, unused, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + impl $name { + /// A string describing the error kind. + pub fn description(&self) -> &str { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) + } + )* + + _ => "", + } + } + } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*} + ) => { + |impl_error_chain_kind!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { + write_internal!(f, $( $exprs )*) + } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern, $( $exprs )*) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $tail )*}) + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { } + ) => { + |self_: &$name, f: &mut ::std::fmt::Formatter| { + write_internal!(f, "{}", self_.description()) + } + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { description($expr:expr) $( $tail:tt )*} + ) => { + $expr + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode $me $fmt [$( $var ),*] + {$( $tail )*}) + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { } + ) => { + stringify_internal!($item) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT + ) => { }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE + [$( $typ:ty ),*] + ) => { + ($( $typ ),*) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + ) => { + {$( $var:$typ ),*} + }; + (ITEM_PATTERN $name:ident $item:ident: UNIT [] + ) => { + $name::$item + }; + (ITEM_PATTERN $name:ident $item:ident: TUPLE + [$( ref $var:ident ),*] + ) => { + $name::$item ($( ref $var ),*) + }; + (ITEM_PATTERN $name:ident $item:ident: STRUCT + [$( ref $var:ident ),*] + ) => { + $name::$item {$( ref $var ),*} + }; + // This one should match all allowed sequences in "funcs" but not match + // anything else. + // This is to contrast FIND_* clauses which just find stuff they need and + // skip everything else completely + (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt ) => {}; + (ERROR_CHECK_COMMA $imode:tt , $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK_COMMA $imode:tt $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + // Utility functions + (IDENT $ident:ident) => { $ident } +} diff --git a/third_party/rust/error-chain/src/lib.rs b/third_party/rust/error-chain/src/lib.rs new file mode 100644 index 0000000000..43d2d5f479 --- /dev/null +++ b/third_party/rust/error-chain/src/lib.rs @@ -0,0 +1,824 @@ +#![deny(missing_docs)] +#![doc(html_root_url = "https://docs.rs/error-chain/0.12.4")] + +//! A library for consistent and reliable error handling +//! +//! error-chain makes it easy to take full advantage of Rust's +//! powerful error handling features without the overhead of +//! maintaining boilerplate error types and conversions. It implements +//! an opinionated strategy for defining your own error types, as well +//! as conversions from others' error types. +//! +//! ## Quick start +//! +//! If you just want to set up your new project with error-chain, +//! follow the [quickstart.rs] template, and read this [intro] +//! to error-chain. +//! +//! [quickstart.rs]: https://github.com/rust-lang-nursery/error-chain/blob/master/examples/quickstart.rs +//! [intro]: http://brson.github.io/2016/11/30/starting-with-error-chain +//! +//! ## Why error chain? +//! +//! * error-chain is easy to configure. Handle errors robustly with minimal +//! effort. +//! * Basic error handling requires no maintenance of custom error types +//! nor the [`From`] conversions that make `?` work. +//! * error-chain scales from simple error handling strategies to more +//! rigorous. Return formatted strings for simple errors, only +//! introducing error variants and their strong typing as needed for +//! advanced error recovery. +//! * error-chain makes it trivial to correctly manage the [cause] of +//! the errors generated by your own code. This is the "chaining" +//! in "error-chain". +//! +//! [cause]: https://doc.rust-lang.org/std/error/trait.Error.html#method.cause +//! +//! ## Principles of error-chain +//! +//! error-chain is based on the following principles: +//! +//! * No error should ever be discarded. This library primarily +//! makes it easy to "chain" errors with the [`chain_err`] method. +//! * Introducing new errors is trivial. Simple errors can be introduced +//! at the error site with just a string. +//! * Handling errors is possible with pattern matching. +//! * Conversions between error types are done in an automatic and +//! consistent way - [`From`] conversion behavior is never specified +//! explicitly. +//! * Errors implement [`Send`]. +//! * Errors can carry backtraces. +//! +//! Similar to other libraries like [error-type] and [quick-error], +//! this library introduces the error chaining mechanism originally +//! employed by Cargo. The [`error_chain!`] macro declares the types +//! and implementation boilerplate necessary for fulfilling a +//! particular error-handling strategy. Most importantly it defines a +//! custom error type (called [`Error`] by convention) and the [`From`] +//! conversions that let the `?` operator work. +//! +//! This library differs in a few ways from previous error libs: +//! +//! * Instead of defining the custom [`Error`] type as an enum, it is a +//! struct containing an [`ErrorKind`][] (which defines the +//! [`description`] and [`display_chain`] methods for the error), an opaque, +//! optional, boxed [`std::error::Error`]` + `[`Send`]` + 'static` object +//! (which defines the [`cause`], and establishes the links in the +//! error chain), and a [`Backtrace`]. +//! * The macro also defines a [`ResultExt`] trait that defines a +//! [`chain_err`] method. This method on all [`std::error::Error`]` + `[`Send`]` + 'static` +//! types extends the error chain by boxing the current +//! error into an opaque object and putting it inside a new concrete +//! error. +//! * It provides automatic [`From`] conversions between other error types +//! defined by the [`error_chain!`] that preserve type information, +//! and facilitate seamless error composition and matching of composed +//! errors. +//! * It provides automatic [`From`] conversions between any other error +//! type that hides the type of the other error in the [`cause`] box. +//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at +//! the earliest opportunity and propagates it down the stack through +//! [`From`] and [`ResultExt`] conversions. +//! +//! To accomplish its goals it makes some tradeoffs: +//! +//! * The split between the [`Error`] and [`ErrorKind`] types can make it +//! slightly more cumbersome to instantiate new (unchained) errors, +//! requiring an [`Into`] or [`From`] conversion; as well as slightly +//! more cumbersome to match on errors with another layer of types +//! to match. +//! * Because the error type contains [`std::error::Error`]` + `[`Send`]` + 'static` objects, +//! it can't implement [`PartialEq`] for easy comparisons. +//! +//! ## Declaring error types +//! +//! Generally, you define one family of error types per crate, though +//! it's also perfectly fine to define error types on a finer-grained +//! basis, such as per module. +//! +//! Assuming you are using crate-level error types, typically you will +//! define an `errors` module and inside it call [`error_chain!`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod other_error { +//! error_chain! {} +//! } +//! +//! error_chain! { +//! // The type defined for this error. These are the conventional +//! // and recommended names, but they can be arbitrarily chosen. +//! // +//! // It is also possible to leave this section out entirely, or +//! // leave it empty, and these names will be used automatically. +//! types { +//! Error, ErrorKind, ResultExt, Result; +//! } +//! +//! // Without the `Result` wrapper: +//! // +//! // types { +//! // Error, ErrorKind, ResultExt; +//! // } +//! +//! // Automatic conversions between this error chain and other +//! // error chains. In this case, it will e.g. generate an +//! // `ErrorKind` variant called `Another` which in turn contains +//! // the `other_error::ErrorKind`, with conversions from +//! // `other_error::Error`. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! links { +//! Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)]; +//! } +//! +//! // Automatic conversions between this error chain and other +//! // error types not defined by the `error_chain!`. These will be +//! // wrapped in a new error with, in the first case, the +//! // `ErrorKind::Fmt` variant. The description and cause will +//! // forward to the description and cause of the original error. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! foreign_links { +//! Fmt(::std::fmt::Error); +//! Io(::std::io::Error) #[cfg(unix)]; +//! } +//! +//! // Define additional `ErrorKind` variants. Define custom responses with the +//! // `description` and `display` calls. +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! +//! // You can also add commas after description/display. +//! // This may work better with some editor auto-indentation modes: +//! UnknownToolchainVersion(v: String) { +//! description("unknown toolchain version"), // note the , +//! display("unknown toolchain version: '{}'", v), // trailing comma is allowed +//! } +//! } +//! +//! // If this annotation is left off, a variant `Msg(s: String)` will be added, and `From` +//! // impls will be provided for `String` and `&str` +//! skip_msg_variant +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Each section, `types`, `links`, `foreign_links`, and `errors` may +//! be omitted if it is empty. +//! +//! This populates the module with a number of definitions, +//! the most important of which are the [`Error`] type +//! and the [`ErrorKind`] type. An example of generated code can be found in the +//! [example_generated](example_generated/index.html) module. +//! +//! ## Returning new errors +//! +//! Introducing new error chains, with a string message: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! fn foo() -> Result<()> { +//! Err("foo error!".into()) +//! } +//! ``` +//! +//! Introducing new error chains, with an [`ErrorKind`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! error_chain! { +//! errors { FooError } +//! } +//! +//! fn foo() -> Result<()> { +//! Err(ErrorKind::FooError.into()) +//! } +//! ``` +//! +//! Note that the return type is the typedef [`Result`], which is +//! defined by the macro as `pub type Result<T> = +//! ::std::result::Result<T, Error>`. Note that in both cases +//! [`.into()`] is called to convert a type into the [`Error`] type; both +//! strings and [`ErrorKind`] have [`From`] conversions to turn them into +//! [`Error`]. +//! +//! When the error is emitted behind the `?` operator, the explicit conversion +//! isn't needed; `Err(ErrorKind)` will automatically be converted to `Err(Error)`. +//! So the below is equivalent to the previous: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! Ok(Err(ErrorKind::FooError)?) +//! } +//! +//! fn bar() -> Result<()> { +//! Ok(Err("bogus!")?) +//! } +//! ``` +//! +//! ## The `bail!` macro +//! +//! The above method of introducing new errors works but is a little +//! verbose. Instead, we can use the [`bail!`] macro, which performs an early return +//! with conversions done automatically. +//! +//! With [`bail!`] the previous examples look like: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! if true { +//! bail!(ErrorKind::FooError); +//! } else { +//! Ok(()) +//! } +//! } +//! +//! fn bar() -> Result<()> { +//! if true { +//! bail!("bogus!"); +//! } else { +//! Ok(()) +//! } +//! } +//! ``` +//! +//! ## Chaining errors +//! error-chain supports extending an error chain by appending new errors. +//! This can be done on a Result or on an existing Error. +//! +//! To extend the error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_something().chain_err(|| "something went wrong"); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`chain_err`] can be called on any [`Result`] type where the contained +//! error type implements [`std::error::Error`]` + `[`Send`]` + 'static`, as long as +//! the [`Result`] type's corresponding [`ResultExt`] trait is in scope. If +//! the [`Result`] is an `Err` then [`chain_err`] evaluates the closure, +//! which returns *some type that can be converted to [`ErrorKind`]*, +//! boxes the original error to store as the cause, then returns a new +//! error containing the original error. +//! +//! Calling [`chain_err`][Error_chain_err] on an existing [`Error`] instance has +//! the same signature and produces the same outcome as being called on a +//! [`Result`] matching the properties described above. This is most useful when +//! partially handling errors using the [`map_err`] function. +//! +//! To chain an error directly, use [`with_chain`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = +//! do_something().map_err(|e| Error::with_chain(e, "something went wrong")); +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Linking errors +//! +//! To convert an error from another error chain to this error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # mod other { error_chain! {} } +//! error_chain! { +//! links { +//! OtherError(other::Error, other::ErrorKind); +//! } +//! } +//! +//! fn do_other_thing() -> other::Result<()> { unimplemented!() } +//! +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_other_thing().map_err(|e| e.into()); +//! # Ok(()) +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types implements [`From`] for the corresponding +//! types of all linked error chains. Linked errors do not introduce a new +//! cause to the error chain. +//! +//! ## Matching errors +//! +//! error-chain error variants are matched with simple patterns. +//! [`Error`] is a tuple struct and its first field is the [`ErrorKind`], +//! making dispatching on error kinds relatively compact: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() { +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! match Error::from("error!") { +//! Error(ErrorKind::InvalidToolchainName(_), _) => { } +//! Error(ErrorKind::Msg(_), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! Chained errors are also matched with (relatively) compact syntax +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod utils { +//! error_chain! { +//! errors { +//! BadStuff { +//! description("bad stuff") +//! } +//! } +//! } +//! } +//! +//! mod app { +//! error_chain! { +//! links { +//! Utils(::utils::Error, ::utils::ErrorKind); +//! } +//! } +//! } +//! +//! +//! # fn main() { +//! match app::Error::from("error!") { +//! app::Error(app::ErrorKind::Utils(utils::ErrorKind::BadStuff), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! ## Inspecting errors +//! +//! An error-chain error contains information about the error itself, a backtrace, and the chain +//! of causing errors. For reporting purposes, this information can be accessed as follows. +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! use error_chain::ChainedError; // for e.display_chain() +//! +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! # fn main() { +//! // Generate an example error to inspect: +//! let e = "xyzzy".parse::<i32>() +//! .chain_err(|| ErrorKind::InvalidToolchainName("xyzzy".to_string())) +//! .unwrap_err(); +//! +//! // Get the brief description of the error: +//! assert_eq!(e.description(), "invalid toolchain name"); +//! +//! // Get the display version of the error: +//! assert_eq!(e.to_string(), "invalid toolchain name: 'xyzzy'"); +//! +//! // Get the full cause and backtrace: +//! println!("{}", e.display_chain().to_string()); +//! // Error: invalid toolchain name: 'xyzzy' +//! // Caused by: invalid digit found in string +//! // stack backtrace: +//! // 0: 0x7fa9f684fc94 - backtrace::backtrace::libunwind::trace +//! // at src/backtrace/libunwind.rs:53 +//! // - backtrace::backtrace::trace<closure> +//! // at src/backtrace/mod.rs:42 +//! // 1: 0x7fa9f6850b0e - backtrace::capture::{{impl}}::new +//! // at out/capture.rs:79 +//! // [..] +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types also allow programmatic access to these elements. +//! +//! ## Foreign links +//! +//! Errors that do not conform to the same conventions as this library +//! can still be included in the error chain. They are considered "foreign +//! errors", and are declared using the `foreign_links` block of the +//! [`error_chain!`] macro. [`Error`]s are automatically created from +//! foreign errors by the `?` operator. +//! +//! Foreign links and regular links have one crucial difference: +//! [`From`] conversions for regular links *do not introduce a new error +//! into the error chain*, while conversions for foreign links *always +//! introduce a new error into the error chain*. So for the example +//! above all errors deriving from the [`std::fmt::Error`] type will be +//! presented to the user as a new [`ErrorKind`] variant, and the +//! cause will be the original [`std::fmt::Error`] error. In contrast, when +//! `other_error::Error` is converted to `Error` the two `ErrorKind`s +//! are converted between each other to create a new `Error` but the +//! old error is discarded; there is no "cause" created from the +//! original error. +//! +//! ## Backtraces +//! +//! If the `RUST_BACKTRACE` environment variable is set to anything +//! but ``0``, the earliest non-foreign error to be generated creates +//! a single backtrace, which is passed through all [`From`] conversions +//! and [`chain_err`] invocations of compatible types. To read the +//! backtrace just call the [`backtrace`] method. +//! +//! Backtrace generation can be disabled by turning off the `backtrace` feature. +//! +//! The Backtrace contains a Vec of [`BacktraceFrame`]s that can be operated +//! on directly. For example, to only see the files and line numbers of code +//! within your own project. +//! +//! ``` +//! # #[macro_use] +//! # extern crate error_chain; +//! # mod errors { +//! # error_chain! { +//! # foreign_links { +//! # Io(::std::io::Error); +//! # } +//! # } +//! # } +//! # use errors::*; +//! # #[cfg(feature="backtrace")] +//! # fn main() { +//! if let Err(ref e) = open_file() { +//! if let Some(backtrace) = e.backtrace() { +//! let frames = backtrace.frames(); +//! for frame in frames.iter() { +//! for symbol in frame.symbols().iter() { +//! if let (Some(file), Some(lineno)) = (symbol.filename(), symbol.lineno()) { +//! if file.display().to_string()[0..3] == "src".to_string(){ +//! println!("{}:{}", file.display().to_string(), lineno); +//! } +//! } +//! } +//! } +//! } +//! }; +//! # } +//! # #[cfg(not(feature="backtrace"))] +//! # fn main() { } +//! +//! fn open_file() -> Result<()> { +//! std::fs::File::open("does_not_exist")?; +//! Ok(()) +//! } +//! ``` +//! +//! ## Iteration +//! +//! The [`iter`] method returns an iterator over the chain of error boxes. +//! +//! [error-type]: https://github.com/DanielKeep/rust-error-type +//! [quick-error]: https://github.com/tailhook/quick-error + +//! [`display_chain`]: trait.ChainedError.html#method.display_chain +//! [`error_chain!`]: macro.error_chain.html +//! [`bail!`]: macro.bail.html +//! [`Backtrace`]: struct.Backtrace.html + +//! [`Error`]: example_generated/struct.Error.html +//! [`with_chain`]: example_generated/struct.Error.html#method.with_chain +//! [Error_chain_err]: example_generated/struct.Error.html#method.chain_err +//! [`cause`]: example_generated/struct.Error.html#method.cause +//! [`backtrace`]: example_generated/struct.Error.html#method.backtrace +//! [`iter`]: example_generated/struct.Error.html#method.iter +//! [`ErrorKind`]: example_generated/enum.ErrorKind.html +//! [`description`]: example_generated/enum.ErrorKind.html#method.description +//! [`Result`]: example_generated/type.Result.html +//! [`ResultExt`]: example_generated/trait.ResultExt.html +//! [`chain_err`]: example_generated/trait.ResultExt.html#tymethod.chain_err + +//! [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html +//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html +//! [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html +//! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +//! [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +//! [`std::fmt::Error`]: https://doc.rust-lang.org/std/fmt/struct.Error.html +//! [`.into()`]: https://doc.rust-lang.org/std/convert/trait.Into.html#tymethod.into +//! [`map_err`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err +//! [`BacktraceFrame`]: https://docs.rs/backtrace/0.3.2/backtrace/struct.BacktraceFrame.html + +use std::error; +use std::fmt; +use std::iter::Iterator; + +#[macro_use] +mod impl_error_chain_kind; +#[macro_use] +mod error_chain; +#[macro_use] +mod quick_main; +pub use quick_main::ExitCode; +mod backtrace; +#[cfg(feature = "example_generated")] +pub mod example_generated; +pub use backtrace::Backtrace; +#[doc(hidden)] +pub use backtrace::InternalBacktrace; + +#[derive(Debug)] +#[allow(unknown_lints, bare_trait_objects)] +/// Iterator over the error chain using the `Error::cause()` method. +pub struct Iter<'a>(Option<&'a error::Error>); + +impl<'a> Iter<'a> { + /// Returns a new iterator over the error chain using `Error::cause()`. + #[allow(unknown_lints, bare_trait_objects)] + pub fn new(err: Option<&'a error::Error>) -> Iter<'a> { + Iter(err) + } +} + +#[allow(unknown_lints, bare_trait_objects)] +impl<'a> Iterator for Iter<'a> { + type Item = &'a error::Error; + + fn next<'b>(&'b mut self) -> Option<&'a error::Error> { + match self.0.take() { + Some(e) => { + self.0 = match () { + #[cfg(not(has_error_source))] + () => e.cause(), + #[cfg(has_error_source)] + () => e.source(), + }; + Some(e) + } + None => None, + } + } +} + +/// This trait is implemented on all the errors generated by the `error_chain` +/// macro. +pub trait ChainedError: error::Error + Send + 'static { + /// Associated kind type. + type ErrorKind; + + /// Constructs an error from a kind, and generates a backtrace. + fn from_kind(kind: Self::ErrorKind) -> Self + where + Self: Sized; + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + fn with_chain<E, K>(error: E, kind: K) -> Self + where + Self: Sized, + E: ::std::error::Error + Send + 'static, + K: Into<Self::ErrorKind>; + + /// Returns the kind of the error. + fn kind(&self) -> &Self::ErrorKind; + + /// Iterates over the error chain. + fn iter(&self) -> Iter; + + /// Returns the backtrace associated with this error. + fn backtrace(&self) -> Option<&Backtrace>; + + /// Returns an object which implements `Display` for printing the full + /// context of this error. + /// + /// The full cause chain and backtrace, if present, will be printed. + fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self> { + DisplayChain(self) + } + + /// Extends the error chain with a new entry. + fn chain_err<F, EK>(self, error: F) -> Self + where + F: FnOnce() -> EK, + EK: Into<Self::ErrorKind>; + + /// Creates an error from its parts. + #[doc(hidden)] + fn new(kind: Self::ErrorKind, state: State) -> Self + where + Self: Sized; + + /// Returns the first known backtrace, either from its State or from one + /// of the errors from `foreign_links`. + #[doc(hidden)] + #[allow(unknown_lints, bare_trait_objects)] + fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option<InternalBacktrace> + where + Self: Sized; +} + +/// A struct which formats an error for output. +#[derive(Debug)] +pub struct DisplayChain<'a, T: 'a + ?Sized>(&'a T); + +impl<'a, T> fmt::Display for DisplayChain<'a, T> +where + T: ChainedError, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + writeln!(fmt, "Error: {}", self.0)?; + + for e in self.0.iter().skip(1) { + writeln!(fmt, "Caused by: {}", e)?; + } + + if let Some(backtrace) = ChainedError::backtrace(self.0) { + writeln!(fmt, "{:?}", backtrace)?; + } + + Ok(()) + } +} + +/// Common state between errors. +#[derive(Debug)] +#[doc(hidden)] +#[allow(unknown_lints, bare_trait_objects)] +pub struct State { + /// Next error in the error chain. + pub next_error: Option<Box<error::Error + Send>>, + /// Backtrace for the current error. + pub backtrace: InternalBacktrace, +} + +impl Default for State { + fn default() -> State { + State { + next_error: None, + backtrace: InternalBacktrace::new(), + } + } +} + +impl State { + /// Creates a new State type + #[allow(unknown_lints, bare_trait_objects)] + pub fn new<CE: ChainedError>(e: Box<error::Error + Send>) -> State { + let backtrace = CE::extract_backtrace(&*e).unwrap_or_else(InternalBacktrace::new); + State { + next_error: Some(e), + backtrace: backtrace, + } + } + + /// Returns the inner backtrace if present. + pub fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_backtrace() + } +} + +/// Exits a function early with an error +/// +/// The `bail!` macro provides an easy way to exit a function. +/// `bail!(expr)` is equivalent to writing. +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let expr = ""; +/// return Err(expr.into()); +/// # } +/// ``` +/// +/// And as shorthand it takes a formatting string a la `println!`: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let n = 0; +/// bail!("bad number: {}", n); +/// # } +/// ``` +/// +/// # Examples +/// +/// Bailing on a custom error: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { +/// errors { FooError } +/// } +/// +/// fn foo() -> Result<()> { +/// if bad_condition() { +/// bail!(ErrorKind::FooError); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> bool { true } +/// ``` +/// +/// Bailing on a formatted string: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { } +/// +/// fn foo() -> Result<()> { +/// if let Some(bad_num) = bad_condition() { +/// bail!("so bad: {}", bad_num); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> Option<i8> { None } +/// ``` +#[macro_export] +macro_rules! bail { + ($e:expr) => { + return Err($e.into()); + }; + ($fmt:expr, $($arg:tt)+) => { + return Err(format!($fmt, $($arg)+).into()); + }; +} + +/// Exits a function early with an error if the condition is not satisfied +/// +/// The `ensure!` macro is a convenience helper that provides a way to exit +/// a function with an error if the given condition fails. +/// +/// As an example, `ensure!(condition, "error code: {}", errcode)` is equivalent to +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let errcode = 0u8; +/// # let condition = true; +/// if !condition { +/// bail!("error code: {}", errcode); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// See documentation for `bail!` macro for further details. +#[macro_export(local_inner_macros)] +macro_rules! ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + bail!($e); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)+) => { + if !($cond) { + bail!($fmt, $($arg)+); + } + }; +} + +#[doc(hidden)] +pub mod mock { + error_chain! {} +} diff --git a/third_party/rust/error-chain/src/quick_main.rs b/third_party/rust/error-chain/src/quick_main.rs new file mode 100644 index 0000000000..a6f093d2b3 --- /dev/null +++ b/third_party/rust/error-chain/src/quick_main.rs @@ -0,0 +1,81 @@ +/// Convenient wrapper to be able to use `?` and such in the main. You can +/// use it with a separated function: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result<()> { +/// Err("error".into()) +/// } +/// ``` +/// +/// or with a closure: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(|| -> Result<()> { +/// Err("error".into()) +/// }); +/// # } +/// ``` +/// +/// You can also set the exit value of the process by returning a type that implements [`ExitCode`](trait.ExitCode.html): +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result<i32> { +/// Err("error".into()) +/// } +/// ``` +#[macro_export] +macro_rules! quick_main { + ($main:expr) => { + fn main() { + use std::io::Write; + + ::std::process::exit(match $main() { + Ok(ret) => $crate::ExitCode::code(ret), + Err(ref e) => { + write!( + &mut ::std::io::stderr(), + "{}", + $crate::ChainedError::display_chain(e) + ) + .expect("Error writing to stderr"); + + 1 + } + }); + } + }; +} + +/// Represents a value that can be used as the exit status of the process. +/// See [`quick_main!`](macro.quick_main.html). +pub trait ExitCode { + /// Returns the value to use as the exit status. + fn code(self) -> i32; +} + +impl ExitCode for i32 { + fn code(self) -> i32 { + self + } +} + +impl ExitCode for () { + fn code(self) -> i32 { + 0 + } +} diff --git a/third_party/rust/error-chain/tests/quick_main.rs b/third_party/rust/error-chain/tests/quick_main.rs new file mode 100644 index 0000000000..4ada3b4e03 --- /dev/null +++ b/third_party/rust/error-chain/tests/quick_main.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] +#[macro_use] +extern crate error_chain; + +error_chain!(); + +mod unit { + use super::*; + quick_main!(run); + + fn run() -> Result<()> { + Ok(()) + } +} + +mod i32 { + use super::*; + quick_main!(run); + + fn run() -> Result<i32> { + Ok(1) + } +} + +mod closure { + use super::*; + quick_main!(|| -> Result<()> { Ok(()) }); +} diff --git a/third_party/rust/error-chain/tests/tests.rs b/third_party/rust/error-chain/tests/tests.rs new file mode 100644 index 0000000000..e9d183c577 --- /dev/null +++ b/third_party/rust/error-chain/tests/tests.rs @@ -0,0 +1,719 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate error_chain; + +#[test] +fn smoke_test_1() { + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_2() { + error_chain! { + types { } + + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_3() { + error_chain! { + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_4() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_5() { + error_chain! { + types { } + + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_6() { + error_chain! { + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_7() { + error_chain! { + types { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_8() { + error_chain! { + types { } + + links { } + links { } + + foreign_links { } + foreign_links { } + + errors { + FileNotFound + AccessDenied + } + }; +} + +#[test] +fn order_test_1() { + error_chain! { types { } links { } foreign_links { } errors { } }; +} + +#[test] +fn order_test_2() { + error_chain! { links { } types { } foreign_links { } errors { } }; +} + +#[test] +fn order_test_3() { + error_chain! { foreign_links { } links { } errors { } types { } }; +} + +#[test] +fn order_test_4() { + error_chain! { errors { } types { } foreign_links { } }; +} + +#[test] +fn order_test_5() { + error_chain! { foreign_links { } types { } }; +} + +#[test] +fn order_test_6() { + error_chain! { + links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + + + foreign_links { } + }; +} + +#[test] +fn order_test_7() { + error_chain! { + links { } + + foreign_links { } + + types { + Error, ErrorKind, ResultExt, Result; + } + }; +} + +#[test] +fn order_test_8() { + error_chain! { + links { } + + foreign_links { } + foreign_links { } + + types { + Error, ErrorKind, ResultExt, Result; + } + }; +} + +#[test] +fn empty() { + error_chain! {}; +} + +#[test] +#[cfg(feature = "backtrace")] +fn has_backtrace_depending_on_env() { + use std::path::PathBuf; + use std::process::Command; + + let cmd_folder = if cfg!(build = "debug") { + "debug" + } else if cfg!(build = "release") { + "release" + } else { + panic!("Unknown build config"); + }; + + let cmd_path = if cfg!(windows) { + PathBuf::from(format!( + "./target/{}/examples/has_backtrace.exe", + cmd_folder + )) + } else { + PathBuf::from(format!("./target/{}/examples/has_backtrace", cmd_folder)) + }; + let mut cmd = Command::new(cmd_path); + + // missing RUST_BACKTRACE and RUST_BACKTRACE=0 + cmd.env_remove("RUST_BACKTRACE"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 0); + + cmd.env("RUST_BACKTRACE", "0"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 0); + + // RUST_BACKTRACE set to anything but 0 + cmd.env("RUST_BACKTRACE", "yes"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 1); + + cmd.env("RUST_BACKTRACE", "1"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 1); +} + +#[test] +fn chain_err() { + use std::fmt; + + error_chain! { + foreign_links { + Fmt(fmt::Error); + } + errors { + Test + } + } + + let _: Result<()> = Err(fmt::Error).chain_err(|| ""); + let _: Result<()> = Err(Error::from_kind(ErrorKind::Test)).chain_err(|| ""); +} + +/// Verify that an error chain is extended one by `Error::chain_err`, with +/// the new error added to the end. +#[test] +fn error_chain_err() { + error_chain! { + errors { + Test + } + } + + let base = Error::from(ErrorKind::Test); + let ext = base.chain_err(|| "Test passes"); + + if let Error(ErrorKind::Msg(_), _) = ext { + // pass + } else { + panic!("The error should be wrapped. {:?}", ext); + } +} + +#[test] +fn links() { + mod test { + error_chain! {} + } + + error_chain! { + links { + Test(test::Error, test::ErrorKind); + } + } +} + +#[cfg(test)] +mod foreign_link_test { + + use std::fmt; + + // Note: foreign errors must be `pub` because they appear in the + // signature of the public foreign_link_error_path + #[derive(Debug)] + pub struct ForeignError { + cause: ForeignErrorCause, + } + + impl ::std::error::Error for ForeignError { + fn description(&self) -> &'static str { + "Foreign error description" + } + + #[cfg(not(has_error_source))] + fn cause(&self) -> Option<&::std::error::Error> { + Some(&self.cause) + } + + #[cfg(has_error_source)] + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + Some(&self.cause) + } + } + + impl fmt::Display for ForeignError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Foreign error display") + } + } + + #[derive(Debug)] + pub struct ForeignErrorCause {} + + impl ::std::error::Error for ForeignErrorCause { + fn description(&self) -> &'static str { + "Foreign error cause description" + } + + #[cfg(not(has_error_source))] + fn cause(&self) -> Option<&::std::error::Error> { + None + } + + #[cfg(has_error_source)] + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } + } + + impl fmt::Display for ForeignErrorCause { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Foreign error cause display") + } + } + + error_chain! { + types{ + Error, ErrorKind, ResultExt, Result; + } + links {} + foreign_links { + Foreign(ForeignError); + Io(::std::io::Error); + } + errors {} + } + + #[test] + fn display_underlying_error() { + let chained_error = try_foreign_error().err().unwrap(); + assert_eq!( + format!( + "{}", + ForeignError { + cause: ForeignErrorCause {} + } + ), + format!("{}", chained_error) + ); + } + + #[test] + #[cfg(not(has_error_source))] + fn finds_cause() { + let chained_error = try_foreign_error().err().unwrap(); + assert_eq!( + format!("{}", ForeignErrorCause {}), + format!("{}", ::std::error::Error::cause(&chained_error).unwrap()) + ); + } + + #[test] + #[cfg(has_error_source)] + fn finds_source() { + let chained_error = try_foreign_error().err().unwrap(); + assert_eq!( + format!("{}", ForeignErrorCause {}), + format!("{}", ::std::error::Error::source(&chained_error).unwrap()) + ); + } + + #[test] + #[allow(unknown_lints, bare_trait_objects)] + fn iterates() { + let chained_error = try_foreign_error().err().unwrap(); + let mut error_iter = chained_error.iter(); + assert!(!format!("{:?}", error_iter).is_empty()); + assert_eq!( + format!( + "{}", + ForeignError { + cause: ForeignErrorCause {} + } + ), + format!("{}", error_iter.next().unwrap()) + ); + assert_eq!( + format!("{}", ForeignErrorCause {}), + format!("{}", error_iter.next().unwrap()) + ); + assert_eq!( + format!("{:?}", None as Option<&::std::error::Error>), + format!("{:?}", error_iter.next()) + ); + } + + fn try_foreign_error() -> Result<()> { + Err(ForeignError { + cause: ForeignErrorCause {}, + })?; + Ok(()) + } +} + +#[cfg(test)] +mod attributes_test { + #[allow(unused_imports)] + use std::io; + + #[cfg(not(test))] + mod inner { + error_chain! {} + } + + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + + links { + Inner(inner::Error, inner::ErrorKind) #[cfg(not(test))]; + } + + foreign_links { + Io(io::Error) #[cfg(not(test))]; + } + + errors { + #[cfg(not(test))] + AnError { + + } + } + } +} + +#[test] +fn with_result() { + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + } + let _: Result<()> = Ok(()); +} + +#[test] +fn without_result() { + error_chain! { + types { + Error, ErrorKind, ResultExt; + } + } + let _: Result<(), ()> = Ok(()); +} + +#[test] +fn documentation() { + mod inner { + error_chain! {} + } + + error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Doc"]; + } + errors { + /// Doc + Variant + } + } +} + +#[cfg(test)] +mod multiple_error_same_mod { + error_chain! { + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + error_chain! {} +} + +#[doc(test)] +#[deny(dead_code)] +mod allow_dead_code { + error_chain! {} +} + +// Make sure links actually work! +#[test] +fn rustup_regression() { + error_chain! { + links { + Download(error_chain::mock::Error, error_chain::mock::ErrorKind); + } + + foreign_links { } + + errors { + LocatingWorkingDir { + description("could not locate working directory") + } + } + } +} + +#[test] +fn error_patterns() { + error_chain! { + links { } + + foreign_links { } + + errors { } + } + + // Tuples look nice when matching errors + match Error::from("Test") { + Error(ErrorKind::Msg(_), _) => {} + _ => {} + } +} + +#[test] +fn result_match() { + error_chain! {} + + fn ok() -> Result<()> { + Ok(()) + } + + match ok() { + Ok(()) => {} + Err(Error(ErrorKind::Msg(_), _)) => {} + Err(..) => {} + } +} + +#[test] +fn error_first() { + error_chain! { + errors { + LocatingWorkingDir { + description("could not locate working directory") + } + } + + links { + Download(error_chain::mock::Error, error_chain::mock::ErrorKind); + } + + foreign_links { } + } +} + +#[test] +fn bail() { + error_chain! { + errors { Foo } + } + + fn foo() -> Result<()> { + bail!(ErrorKind::Foo) + } + + fn bar() -> Result<()> { + bail!("bar") + } + + fn baz() -> Result<()> { + bail!("{}", "baz") + } +} + +#[test] +fn ensure() { + error_chain! { + errors { Bar } + } + + fn foo(x: u8) -> Result<()> { + ensure!(x == 42, ErrorKind::Bar); + Ok(()) + } + + assert!(foo(42).is_ok()); + assert!(foo(0).is_err()); +} + +/// Since the `types` declaration is a list of symbols, check if we +/// don't change their meaning or order. +#[test] +fn types_declarations() { + error_chain! { + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + + MyError::from_kind(MyErrorKind::Msg("".into())); + + let err: Result<(), ::std::io::Error> = Ok(()); + MyResultExt::chain_err(err, || "").unwrap(); + + let _: MyResult<()> = Ok(()); +} + +#[test] +/// Calling chain_err over a `Result` containing an error to get a chained error +/// and constructing a MyError directly, passing it an error should be equivalent. +fn rewrapping() { + use std::env::VarError::{self, NotPresent, NotUnicode}; + + error_chain! { + foreign_links { + VarErr(VarError); + } + + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + + let result_a_from_func: Result<String, _> = Err(VarError::NotPresent); + let result_b_from_func: Result<String, _> = Err(VarError::NotPresent); + + let our_error_a = result_a_from_func.map_err(|e| match e { + NotPresent => MyError::with_chain(e, "env var wasn't provided"), + NotUnicode(_) => MyError::with_chain(e, "env var was borkæ–‡å—化ã"), + }); + + let our_error_b = result_b_from_func.or_else(|e| match e { + NotPresent => Err(e).chain_err(|| "env var wasn't provided"), + NotUnicode(_) => Err(e).chain_err(|| "env var was borkæ–‡å—化ã"), + }); + + assert_eq!( + format!("{}", our_error_a.unwrap_err()), + format!("{}", our_error_b.unwrap_err()) + ); +} + +#[test] +fn comma_in_errors_impl() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code"), + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn trailing_comma_in_errors_impl() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code"), + display("http request returned an unsuccessful status code: {}", e), + } + } + }; +} + +#[test] +fn skipping_msg_variant() { + error_chain! { + skip_msg_variant + + errors { + MyMsg(s: String) { + description(&s) + display("{}", s) + } + } + } + + let x = Error::from_kind(ErrorKind::MyMsg("some string".into())); + // This would fail to compile if we generate a `Msg` variant + match *x.kind() { + ErrorKind::MyMsg(_) => {} + ErrorKind::__Nonexhaustive {} => {} + } +} |