├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── RELEASES.md ├── book └── src │ ├── SUMMARY.md │ ├── custom-fail.md │ ├── derive-fail.md │ ├── error-errorkind.md │ ├── error-msg.md │ ├── error.md │ ├── fail.md │ ├── guidance.md │ ├── howto.md │ ├── intro.md │ └── use-error.md ├── build-docs.sh ├── failure-0.1.X ├── Cargo.toml ├── examples │ └── bail_ensure.rs ├── failure_derive │ ├── .gitignore │ ├── .travis.yml │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── tests │ │ ├── backtrace.rs │ │ ├── external_display_derive.rs │ │ ├── no_derive_display.rs │ │ ├── tests.rs │ │ └── wraps.rs └── src │ ├── lib.rs │ └── macros.rs ├── failure-1.X ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── Cargo.toml ├── failure_derive │ ├── .gitignore │ ├── .travis.yml │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── tests │ │ ├── backtrace.rs │ │ ├── no_derive_display.rs │ │ ├── tests.rs │ │ └── wraps.rs └── src │ ├── backtrace │ ├── internal.rs │ └── mod.rs │ ├── compat.rs │ ├── context.rs │ ├── error.rs │ ├── error_message.rs │ ├── lib.rs │ ├── macros.rs │ ├── result_ext.rs │ ├── small_error.rs │ └── sync_failure.rs ├── failure_compat_shim ├── Cargo.toml └── src │ └── lib.rs └── travis.sh /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | **/Cargo.lock 4 | public 5 | book/book 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "rust:latest" 2 | 3 | pages: 4 | script: 5 | - sh ./build-docs.sh 6 | artifacts: 7 | paths: 8 | - public 9 | only: 10 | - master 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | rust: 4 | - 1.18.0 5 | - stable 6 | - beta 7 | - nightly 8 | cache: cargo 9 | script: bash travis.sh 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at boats@mozilla.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # failure - a new error management story 2 | 3 | [![Build Status](https://travis-ci.org/withoutboats/failure.svg?branch=master)](https://travis-ci.org/withoutboats/failure) 4 | [![Latest Version](https://img.shields.io/crates/v/failure.svg)](https://crates.io/crates/failure) 5 | [![docs](https://docs.rs/failure/badge.svg)](https://docs.rs/failure) 6 | 7 | `failure` is designed to make it easier to manage errors in Rust. It is 8 | intended to replace error management based on `std::error::Error` with a new 9 | system based on lessons learned over the past several years, including those 10 | learned from experience with quick-error and error-chain. 11 | 12 | `failure` provides two core components: 13 | 14 | * `Fail`: A new trait for custom error types. 15 | * `Error`: A struct which any type that implements `Fail` can be cast into. 16 | 17 | ## Example 18 | 19 | ```rust 20 | extern crate serde; 21 | extern crate toml; 22 | 23 | #[macro_use] extern crate failure; 24 | #[macro_use] extern crate serde_derive; 25 | 26 | use std::collections::HashMap; 27 | use std::path::PathBuf; 28 | use std::str::FromStr; 29 | 30 | use failure::Error; 31 | 32 | // This is a new error type that you've created. It represents the ways a 33 | // toolchain could be invalid. 34 | // 35 | // The custom derive for Fail derives an impl of both Fail and Display. 36 | // We don't do any other magic like creating new types. 37 | #[derive(Debug, Fail)] 38 | enum ToolchainError { 39 | #[fail(display = "invalid toolchain name: {}", name)] 40 | InvalidToolchainName { 41 | name: String, 42 | }, 43 | #[fail(display = "unknown toolchain version: {}", version)] 44 | UnknownToolchainVersion { 45 | version: String, 46 | } 47 | } 48 | 49 | pub struct ToolchainId { 50 | // ... etc 51 | } 52 | 53 | impl FromStr for ToolchainId { 54 | type Err = ToolchainError; 55 | 56 | fn from_str(s: &str) -> Result { 57 | // ... etc 58 | } 59 | } 60 | 61 | pub type Toolchains = HashMap; 62 | 63 | // This opens a toml file containing associations between ToolchainIds and 64 | // Paths (the roots of those toolchains). 65 | // 66 | // This could encounter an io Error, a toml parsing error, or a ToolchainError, 67 | // all of them will be thrown into the special Error type 68 | pub fn read_toolchains(path: PathBuf) -> Result 69 | { 70 | use std::fs::File; 71 | use std::io::Read; 72 | 73 | let mut string = String::new(); 74 | File::open(path)?.read_to_string(&mut string)?; 75 | 76 | let toml: HashMap = toml::from_str(&string)?; 77 | 78 | let toolchains = toml.iter().map(|(key, path)| { 79 | let toolchain_id = key.parse()?; 80 | Ok((toolchain_id, path)) 81 | }).collect::>()?; 82 | 83 | Ok(toolchains) 84 | } 85 | ``` 86 | 87 | ## Requirements 88 | 89 | Both failure and failure_derive are intended to compile on all stable versions 90 | of Rust newer than 1.18.0, as well as the latest beta and the latest nightly. 91 | If either crate fails to compile on any version newer than 1.18.0, please open 92 | an issue. 93 | 94 | failure is **no_std** compatible, though some aspects of it (primarily the 95 | `Error` type) will not be available in no_std mode. 96 | 97 | ## License 98 | 99 | failure is licensed under the terms of the MIT License or the Apache License 100 | 2.0, at your choosing. 101 | 102 | ## Code of Conduct 103 | 104 | Contribution to the failure crate is organized under the terms of the 105 | Contributor Covenant, the maintainer of failure, @withoutboats, promises to 106 | intervene to uphold that code of conduct. 107 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Version 0.1.1 2 | 3 | - Add a `Causes` iterator, which iterates over the causes of a failure. Can be 4 | accessed through the `Fail::causes` or `Error::causes` methods. 5 | - Add the `bail!` macro, which "throws" from the function. 6 | - Add the `ensure!` macro, which is like an "assert" which throws instead of 7 | panicking. 8 | - The derive now supports a no_std mode. 9 | - The derive is re-exported from `failure` by default, so that users do not 10 | have to directly depend on `failure_derive`. 11 | - Add a impl of `From for Context`, allowing users to `?` the `D` type to 12 | produce a `Context` (for cases where there is no further underlying 13 | error). 14 | 15 | # Version 0.1.0 16 | 17 | - Initial version. 18 | -------------------------------------------------------------------------------- /book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [failure](./intro.md) 4 | - [How to use failure](./howto.md) 5 | - [The Fail trait](./fail.md) 6 | - [Deriving Fail](./derive-fail.md) 7 | - [The Error type](./error.md) 8 | - [Patterns & Guidance](./guidance.md) 9 | - [Strings as errors](./error-msg.md) 10 | - [A Custom Fail type](./custom-fail.md) 11 | - [Using the Error type](./use-error.md) 12 | - [An Error and ErrorKind pair](./error-errorkind.md) 13 | -------------------------------------------------------------------------------- /book/src/custom-fail.md: -------------------------------------------------------------------------------- 1 | # A Custom Fail type 2 | 3 | This pattern is a way to define a new kind of failure. Defining a new kind of 4 | failure can be an effective way of representing an error for which you control 5 | all of the possible failure cases. It has several advantages: 6 | 7 | 1. You can enumerate exactly all of the possible failures that can occur in 8 | this context. 9 | 2. You have total control over the representation of the failure type. 10 | 3. Callers can destructure your error without any sort of downcasting. 11 | 12 | To implement this pattern, you should define your own type that implements 13 | `Fail`. You can use the [custom derive][derive-fail] to make this easier. For 14 | example: 15 | 16 | ```rust 17 | #[derive(Fail, Debug)] 18 | #[fail(display = "Input was invalid UTF-8")] 19 | pub struct Utf8Error; 20 | ``` 21 | 22 | This type can become as large and complicated as is appropriate to your use 23 | case. It can be an enum with a different variant for each possible error, and 24 | it can carry data with more precise information about the error. For example: 25 | 26 | ```rust 27 | #[derive(Fail, Debug)] 28 | #[fail(display = "Input was invalid UTF-8 at index {}", index)] 29 | pub struct Utf8Error { 30 | index: usize, 31 | } 32 | ``` 33 | 34 | ## When might you use this pattern? 35 | 36 | If you need to raise an error that doesn't come from one of your dependencies, 37 | this is a great pattern to use. 38 | 39 | You can also use this pattern in conjunction with [using `Error`][use-error] or 40 | defining an [Error and ErrorKind pair][error-errorkind]. Those functions which 41 | are "pure logic" and have a very constrained set of errors (such as parsing 42 | simple formats) might each return a different custom Fail type, and then the 43 | function which merges them all together, does IO, and so on, would return a 44 | more complex type like `Error` or your custom Error/ErrorKind. 45 | 46 | ## Caveats on this pattern 47 | 48 | When you have a dependency which returns a different error type, often you will 49 | be inclined to add it as a variant on your own error type. When you do that, 50 | you should tag the underlying error as the `#[cause]` of your error: 51 | 52 | ```rust 53 | #[derive(Fail, Debug)] 54 | pub enum MyError { 55 | #[fail(display = "Input was invalid UTF-8 at index {}", _0)] 56 | Utf8Error(usize), 57 | #[fail(display = "{}", _0)] 58 | Io(#[cause] io::Error), 59 | } 60 | ``` 61 | 62 | Up to a limit, this design can work. However, it has some problems: 63 | 64 | - It can be hard to be forward compatible with new dependencies that raise 65 | their own kinds of errors in the future. 66 | - It defines a 1-1 relationship between a variant of the error and an 67 | underlying error. 68 | 69 | Depending on your use case, as your function grows in complexity, it can be 70 | better to transition to [using Error][use-error] or [defining an Error & 71 | ErrorKind pair][error-errorkind]. 72 | 73 | [derive-fail]: ./derive-fail.html 74 | [use-error]: ./use-error.html 75 | [error-errorkind]: ./error-errorkind.html 76 | -------------------------------------------------------------------------------- /book/src/derive-fail.md: -------------------------------------------------------------------------------- 1 | # Deriving `Fail` 2 | 3 | Though you can implement `Fail` yourself, we also provide a derive macro to 4 | generate the impl for you. To get access to this macro, you must tag the extern 5 | crate declaration with `#[macro_use]`, as in: 6 | 7 | ```rust 8 | #[macro_use] extern crate failure; 9 | ``` 10 | 11 | In its smallest form, deriving Fail looks like this: 12 | 13 | ```rust 14 | #[macro_use] extern crate failure; 15 | 16 | use std::fmt; 17 | 18 | #[derive(Fail, Debug)] 19 | struct MyError; 20 | 21 | impl fmt::Display for MyError { 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 23 | write!(f, "An error occurred.") 24 | } 25 | } 26 | ``` 27 | 28 | All failures need to implement `Display`, so we have added an impl of 29 | Display. However, implementing `Display` is much more boilerplate than 30 | implementing `Fail` - this is why we support deriving `Display` for you. 31 | 32 | ## Deriving `Display` 33 | 34 | You can derive an implementation of `Display` with a special attribute: 35 | 36 | ```rust 37 | #[macro_use] extern crate failure; 38 | 39 | #[derive(Fail, Debug)] 40 | #[fail(display = "An error occurred.")] 41 | struct MyError; 42 | ``` 43 | 44 | This attribute will cause the `Fail` derive to also generate an impl of 45 | `Display`, so that you don't have to implement one yourself. 46 | 47 | ### String interpolation 48 | 49 | String literals are not enough for error messages in many cases. Often, you 50 | want to include parts of the error value interpolated into the message. You can 51 | do this with failure using the same string interpolation syntax as Rust's 52 | formatting and printing macros: 53 | 54 | ```rust 55 | #[macro_use] extern crate failure; 56 | 57 | #[derive(Fail, Debug)] 58 | #[fail(display = "An error occurred with error code {}. ({})", code, message)] 59 | struct MyError { 60 | code: i32, 61 | message: String, 62 | } 63 | ``` 64 | 65 | Note that unlike code that would appear in a method, this does not use 66 | something like `self.code` or `self.message`; it just uses the field names 67 | directly. This is because of a limitation in Rust's current attribute syntax. 68 | As a result, you can only interpolate fields through the derivation; you cannot 69 | perform method calls or use other arbitrary expressions. 70 | 71 | ### Tuple structs 72 | 73 | With regular structs, you can use the name of the field in string 74 | interpolation. When deriving Fail for a tuple struct, you might expect to use 75 | the numeric index to refer to fields `0`, `1`, et cetera. However, a compiler 76 | limitation prevents this from parsing today. 77 | 78 | For the time being, tuple field accesses in the display attribute need to be 79 | prefixed with an underscore: 80 | 81 | ```rust 82 | #[macro_use] extern crate failure; 83 | 84 | #[derive(Fail, Debug)] 85 | #[fail(display = "An error occurred with error code {}.", _0)] 86 | struct MyError(i32); 87 | 88 | 89 | #[derive(Fail, Debug)] 90 | #[fail(display = "An error occurred with error code {} ({}).", _0, _1)] 91 | struct MyOtherError(i32, String); 92 | ``` 93 | 94 | ### Enums 95 | 96 | Implementing Display is also supported for enums by applying the attribute to 97 | each variant of the enum, rather than to the enum as a whole. The Display impl 98 | will match over the enum to generate the correct error message. For example: 99 | 100 | ```rust 101 | #[macro_use] extern crate failure; 102 | 103 | #[derive(Fail, Debug)] 104 | enum MyError { 105 | #[fail(display = "{} is not a valid version.", _0)] 106 | InvalidVersion(u32), 107 | #[fail(display = "IO error: {}", error)] 108 | IoError { error: io::Error }, 109 | #[fail(display = "An unknown error has occurred.")] 110 | UnknownError, 111 | } 112 | ``` 113 | 114 | ## Overriding `backtrace` 115 | 116 | The backtrace method will be automatically overridden if the type contains a 117 | field with the type `Backtrace`. This works for both structs and enums. 118 | 119 | ```rust 120 | #[macro_use] extern crate failure; 121 | 122 | use failure::Backtrace; 123 | 124 | /// MyError::backtrace will return a reference to the backtrace field 125 | #[derive(Fail, Debug)] 126 | #[fail(display = "An error occurred.")] 127 | struct MyError { 128 | backtrace: Backtrace, 129 | } 130 | 131 | /// MyEnumError::backtrace will return a reference to the backtrace only if it 132 | /// is Variant2, otherwise it will return None. 133 | #[derive(Fail, Debug)] 134 | enum MyEnumError { 135 | #[fail(display = "An error occurred.")] 136 | Variant1, 137 | #[fail(display = "A different error occurred.")] 138 | Variant2(Backtrace), 139 | } 140 | ``` 141 | 142 | This happens automatically; no other annotations are necessary. It only works 143 | if the type is named Backtrace, and not if you have created an alias for the 144 | Backtrace type. 145 | 146 | ## Overriding `cause` 147 | 148 | In contrast to `backtrace`, the cause cannot be determined by type name alone 149 | because it could be any type which implements `Fail`. For this reason, if your 150 | error has an underlying cause field, you need to annotate that field with 151 | the `#[cause]` attribute. 152 | 153 | This can be used in fields of enums as well as structs. 154 | 155 | 156 | ```rust 157 | #[macro_use] extern crate failure; 158 | 159 | use std::io; 160 | 161 | /// MyError::cause will return a reference to the io_error field 162 | #[derive(Fail, Debug)] 163 | #[fail(display = "An error occurred.")] 164 | struct MyError { 165 | #[cause] io_error: io::Error, 166 | } 167 | 168 | /// MyEnumError::cause will return a reference only if it is Variant2, 169 | /// otherwise it will return None. 170 | #[derive(Fail, Debug)] 171 | enum MyEnumError { 172 | #[fail(display = "An error occurred.")] 173 | Variant1, 174 | #[fail(display = "A different error occurred.")] 175 | Variant2(#[cause] io::Error), 176 | } 177 | ``` 178 | -------------------------------------------------------------------------------- /book/src/error-errorkind.md: -------------------------------------------------------------------------------- 1 | # An Error and ErrorKind pair 2 | 3 | This pattern is the most robust way to manage errors - and also the most high 4 | maintenance. It combines some of the advantages of the [using Error][use-error] 5 | pattern and the [custom failure][custom-fail] patterns, while avoiding some of 6 | the disadvantages each of those patterns has: 7 | 8 | 1. Like `Error`, this is forward compatible with new underlying kinds of 9 | errors from your dependencies. 10 | 2. Like custom failures, this pattern allows you to specify additional information about the error that your dependencies don't give you. 11 | 3. Like `Error`, it can be easier to convert underlying errors from dependency 12 | into this type than for custom failures. 13 | 4. Like custom failures, users can gain some information about the error 14 | without downcasting. 15 | 16 | The pattern is to create two new failure types: an `Error` and an `ErrorKind`, 17 | and to leverage [the `Context` type][context-api] provided by failure. 18 | 19 | ```rust 20 | #[derive(Debug)] 21 | struct MyError { 22 | inner: Context, 23 | } 24 | 25 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] 26 | enum MyErrorKind { 27 | // A plain enum with no data in any of its variants 28 | // 29 | // For example: 30 | #[fail(display = "A contextual error message.")] 31 | OneVariant, 32 | // ... 33 | } 34 | ``` 35 | 36 | Unfortunately, it is not easy to correctly derive `Fail` for `MyError` so that 37 | it delegates things to its inner `Context`. You should write those impls 38 | yourself: 39 | 40 | ```rust 41 | impl Fail for MyError { 42 | fn cause(&self) -> Option<&Fail> { 43 | self.inner.cause() 44 | } 45 | 46 | fn backtrace(&self) -> Option<&Backtrace> { 47 | self.inner.backtrace() 48 | } 49 | } 50 | 51 | impl Display for MyError { 52 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 53 | Display::fmt(&self.inner, f) 54 | } 55 | } 56 | ``` 57 | 58 | You should also provide some conversions and accessors, to go between a 59 | Context, your ErrorKind, and your Error: 60 | 61 | ```rust 62 | impl MyError { 63 | pub fn kind(&self) -> MyErrorKind { 64 | *self.inner.get_context() 65 | } 66 | } 67 | 68 | impl From for MyError { 69 | fn from(kind: MyErrorKind) -> MyError { 70 | MyError { inner: Context::new(kind) } 71 | } 72 | } 73 | 74 | impl From> for MyError { 75 | fn from(inner: Context) -> MyError { 76 | MyError { inner: inner } 77 | } 78 | } 79 | ``` 80 | 81 | With this code set up, you can use the context method from failure to apply 82 | your ErrorKind to errors in underlying libraries: 83 | 84 | ```rust 85 | perform_some_io().context(ErrorKind::NetworkFailure)?; 86 | ``` 87 | 88 | You can also directly throw `ErrorKind` without an underlying error when 89 | appropriate: 90 | 91 | ```rust 92 | Err(ErrorKind::DomainSpecificError)? 93 | ``` 94 | 95 | ### What should your ErrorKind contain? 96 | 97 | Your error kind probably should not carry data - and if it does, it should only 98 | carry stateless data types that provide additional information about what the 99 | `ErrorKind` means. This way, your `ErrorKind` can be `Eq`, making it 100 | easy to use as a way of comparing errors. 101 | 102 | Your ErrorKind is a way of providing information about what errors mean 103 | appropriate to the level of abstraction that your library operates at. As some 104 | examples: 105 | 106 | - If your library expects to read from the user's `Cargo.toml`, you might have 107 | a `InvalidCargoToml` variant, to capture what `io::Error` and `toml::Error` 108 | mean in the context of your library. 109 | - If your library does both file system activity and network activity, you 110 | might have `Filesystem` and `Network` variants, to divide up the `io::Error`s 111 | between which system in particular failed. 112 | 113 | Exactly what semantic information is appropriate depends entirely on what this 114 | bit of code is intended to do. 115 | 116 | ## When might you use this pattern? 117 | 118 | The most likely use cases for this pattern are mid-layer which perform a 119 | function that requires many dependencies, and that are intended to be used in 120 | production. Libraries with few dependencies do not need to manage many 121 | underlying error types and can probably suffice with a simpler [custom 122 | failure][custom-fail]. Applications that know they are almost always just going 123 | to log these errors can get away with [using the Error type][use-error] rather 124 | than managing extra context information. 125 | 126 | That said, when you need to provide the most expressive information about an 127 | error possible, this can be a good approach. 128 | 129 | ## Caveats on this pattern 130 | 131 | This pattern is the most involved pattern documented in this book. It involves 132 | a lot of boilerplate to set up (which may be automated away eventually), and it 133 | requires you to apply a contextual message to every underlying error that is 134 | thrown inside your code. It can be a lot of work to maintain this pattern. 135 | 136 | Additionally, like the Error type, the Context type may use an allocation and a 137 | dynamic dispatch internally. If you know this is too expensive for your use 138 | case, you should not use this pattern. 139 | 140 | [use-error]: ./use-error.html 141 | [custom-fail]: ./custom-fail.html 142 | [context-api]: https://boats.gitlab.io/failure/doc/failure/struct.Context.html 143 | -------------------------------------------------------------------------------- /book/src/error-msg.md: -------------------------------------------------------------------------------- 1 | # Strings as errors 2 | 3 | This pattern is a way to create new errors without doing much set up. It is 4 | definitely the sloppiest way to throw errors. It can be great to use this 5 | during prototyping, but maybe not in the final product. 6 | 7 | String types do not implement `Fail`, which is why there are two adapters to 8 | create failures from a string: 9 | 10 | - [`failure::err_msg`][err-msg-api] - a function that takes a displayable 11 | type and creates a failure from it. This can take a String or a string 12 | literal. 13 | - [`format_err!`][format-err-api] - a macro with string interpolation, similar 14 | to `format!` or `println!`. 15 | 16 | ```rust 17 | fn check_range(x: usize, range: Range) -> Result { 18 | if x < range.start { 19 | return Err(format_err!("{} is below {}", x, range.start)); 20 | } 21 | if x >= range.end { 22 | return Err(format_err!("{} is above {}", x, range.end)); 23 | } 24 | Ok(x) 25 | } 26 | ``` 27 | 28 | If you're going to use strings as errors, we recommend [using 29 | `Error`][use-error] as your error type, rather than `ErrorMessage`; this way, 30 | if some of your strings are `String` and some are `&'static str`, you don't 31 | need worry about merging them into a single string type. 32 | 33 | ## When might you use this pattern? 34 | 35 | This pattern is the easiest to set up and get going with, so it can be great 36 | when prototyping or spiking out an early design. It can also be great when you 37 | know that an error variant is extremely uncommon, and that there is really no 38 | way to handle it other than to log the error and move on. 39 | 40 | ## Caveats on this pattern 41 | 42 | If you are writing a library you plan to publish to crates.io, this is probably 43 | not a good way to handle errors, because it doesn't give your clients very much 44 | control. For public, open source libraries, we'd recommend using [custom 45 | failures][custom-fail] in the cases where you would use a string as an error. 46 | 47 | This pattern can also be very brittle. If you ever want to branch over which 48 | error was returned, you would have to match on the exact contents of the 49 | string. If you ever change the string contents, that will silently break that 50 | match. 51 | 52 | For these reasons, we strongly recommend against using this pattern except for 53 | prototyping and when you know the error is just going to get logged or reported 54 | to the users. 55 | 56 | [custom-fail]: ./custom-fail.html 57 | [use-error]: ./use-error.html 58 | [err-msg-api]: https://boats.gitlab.io/failure/doc/failure/fn.err_msg.html 59 | [format-err-api]: https://boats.gitlab.io/failure/doc/failure/macro.format_err.html 60 | -------------------------------------------------------------------------------- /book/src/error.md: -------------------------------------------------------------------------------- 1 | # The `Error` type 2 | 3 | In addition to the trait `Fail`, failure provides a type called `Error`. Any 4 | type that implements `Fail` can be cast into `Error` using From and Into, which 5 | allows users to throw errors using `?` which have different types, if the 6 | function returns an `Error`. 7 | 8 | For example: 9 | 10 | ```rust 11 | // Something you can deserialize 12 | #[derive(Deserialize)] 13 | struct Object { 14 | ... 15 | } 16 | 17 | impl Object { 18 | // This throws both IO Errors and JSON Errors, but they both get converted 19 | // into the Error type. 20 | fn from_file(path: &Path) -> Result { 21 | let mut string = String::new(); 22 | File::open(path)?.read_to_string(&mut string)?; 23 | let object = json::from_str(&string)?; 24 | Ok(object) 25 | } 26 | } 27 | ``` 28 | 29 | ## Causes and Backtraces 30 | 31 | The Error type has all of the methods from the Fail trait, with a few notable 32 | differences. Most importantly, the cause and backtrace methods on Error do not 33 | return Options - an Error is *guaranteed* to have a cause and a backtrace. 34 | 35 | ```rust 36 | // Both methods are guaranteed to return an &Fail and an &Backtrace 37 | println!("{}, {}", error.cause(), error.backtrace()) 38 | ``` 39 | 40 | An `Error`'s cause is always the failure that was cast into this `Error`. 41 | That failure may have further underlying causes. Unlike Fail, this means that 42 | the cause of an Error will have the same Display representation as the Error 43 | itself. 44 | 45 | As to the error's guaranteed backtrace, when the conversion into the Error type 46 | happens, if the underlying failure does not provide a backtrace, a new 47 | backtrace is constructed pointing to that conversion point (rather than the 48 | origin of the error). This construction only happens if there is no underlying 49 | backtrace; if it does have a backtrace no new backtrace is constructed. 50 | 51 | ## Downcasting 52 | 53 | The Error type also supports downcasting into any concrete Fail type. It can be 54 | downcast by reference or by value - when downcasting by value, the return type 55 | is `Result`, allowing you to get the error back out of it. 56 | 57 | ```rust 58 | match error.downcast::() { 59 | Ok(io_error) => { ... } 60 | Err(error) => { ... } 61 | } 62 | ``` 63 | 64 | ## Implementation details 65 | 66 | `Error` is essentially a trait object, but with some fanciness it may generate 67 | and store the backtrace if the underlying failure did not have one. In 68 | particular, we use a custom dynamically sized type to store the backtrace 69 | information inline with the trait object data. 70 | 71 | ```rust 72 | struct Error { 73 | // Inner is a dynamically sized type 74 | inner: Box>, 75 | } 76 | 77 | struct Inner { 78 | backtrace: Backtrace, 79 | failure: F, 80 | } 81 | ``` 82 | 83 | By storing the backtrace in the heap this way, we avoid increasing the size of 84 | the Error type beyond that of two non-nullable pointers. This keeps the size of 85 | the `Result` type from getting too large, avoiding having a negative impact on 86 | the "happy path" of returning Ok. For example, a `Result<(), Error>` should be 87 | represented as a pair of nullable pointers, with the null case representing 88 | `Ok`. Similar optimizations can be applied to values up to at least a pointer 89 | in size. 90 | 91 | To emphasize: Error is intended for use cases where the error case is 92 | considered relatively uncommon. This optimization makes the overhead of an 93 | error less than it otherwise would be for the Ok branch. In cases where errors 94 | are going to be returned extremely frequently, returning this Error type is 95 | probably not appropriate, but you should benchmark in those cases. 96 | 97 | (As a rule of thumb: if you're not sure if you can afford to have a trait 98 | object, you probably *can* afford it. Heap allocations are not nearly as cheap 99 | as stack allocations, but they're cheap enough that you can almost always 100 | afford them.) 101 | -------------------------------------------------------------------------------- /book/src/fail.md: -------------------------------------------------------------------------------- 1 | # The `Fail` trait 2 | 3 | The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has 4 | been designed to support a number of operations: 5 | 6 | - Because it is bound by both `Debug` and `Display`, any failure can be 7 | printed in two ways. 8 | - It has both a `backtrace` and a `cause` method, allowing users to get 9 | information about how the error occurred. 10 | - It supports wrapping failures in additional contextual information. 11 | - Because it is bound by `Send` and `Sync`, failures can be moved and share 12 | between threads easily. 13 | - Because it is bound by `'static`, the abstract `Fail` trait object can be 14 | downcast into concrete types. 15 | 16 | Every new error type in your code should implement `Fail`, so it can be 17 | integrated into the entire system built around this trait. You can manually 18 | implement `Fail` yourself, or you can use the derive for `Fail` defined 19 | in a separate crate and documented [here][derive-docs]. 20 | 21 | Implementors of this trait are called 'failures'. 22 | 23 | ## Cause 24 | 25 | Often, an error type contains (or could contain) another underlying error type 26 | which represents the "cause" of this error - for example, if your custom error 27 | contains an `io::Error`, that is the cause of your error. 28 | 29 | The cause method on the `Fail` trait allows all errors to expose their underlying 30 | cause - if they have one - in a consistent way. Users can loop over the chain 31 | of causes, for example, getting the entire series of causes for an error: 32 | 33 | ```rust 34 | // Assume err is a type that implements `Fail` 35 | let mut fail: &Fail = err; 36 | 37 | while let Some(cause) = fail.cause() { 38 | println!("{}", cause); 39 | 40 | // Make `fail` the reference to the cause of the previous fail, making the 41 | // loop "dig deeper" into the cause chain. 42 | fail = cause; 43 | } 44 | ``` 45 | 46 | Because `&Fail` supports downcasting, you can also inspect causes in more 47 | detail if you are expecting a certain failure: 48 | 49 | ```rust 50 | while let Some(cause) = fail.cause() { 51 | 52 | if let Some(err) = cause.downcast_ref::() { 53 | // treat io::Error specially 54 | } else { 55 | // fallback case 56 | } 57 | 58 | fail = cause; 59 | } 60 | ``` 61 | 62 | ## Backtraces 63 | 64 | Errors can also generate a backtrace when they are constructed, helping you 65 | determine the place the error was generated and the function chain that called into 66 | that. Like causes, this is entirely optional - the authors of each failure 67 | have to decide if generating a backtrace is appropriate in their use case. 68 | 69 | The backtrace method allows all errors to expose their backtrace if they have 70 | one. This enables a consistent method for getting the backtrace from an error: 71 | 72 | ```rust 73 | // We don't even know the type of the cause, but we can still get its 74 | // backtrace. 75 | if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) { 76 | println!("{}", bt) 77 | } 78 | ``` 79 | 80 | The `Backtrace` type exposed by `failure` is different from the `Backtrace` exposed 81 | by the [backtrace crate][backtrace-crate], in that it has several optimizations: 82 | 83 | - It has a `no_std` compatible form which will never be generated (because 84 | backtraces require heap allocation), and should be entirely compiled out. 85 | - It will not be generated unless the `RUST_BACKTRACE` environment variable has 86 | been set at runtime. 87 | - Symbol resolution is delayed until the backtrace is actually printed, because 88 | this is the most expensive part of generating a backtrace. 89 | 90 | ## Context 91 | 92 | Often, the libraries you are using will present error messages that don't 93 | provide very helpful information about what exactly has gone wrong. For 94 | example, if an `io::Error` says that an entity was "Not Found," that doesn't 95 | communicate much about what specific file was missing - if it even was a file 96 | (as opposed to a directory for example). 97 | 98 | You can inject additional context to be carried with this error value, 99 | providing semantic information about the nature of the error appropriate to the 100 | level of abstraction that the code you are writing operates at. The `context` 101 | method on `Fail` takes any displayable value (such as a string) to act as 102 | context for this error. 103 | 104 | Using the `ResultExt` trait, you can also get `context` as a convenient method on 105 | `Result` directly. For example, suppose that your code attempted to read from a 106 | Cargo.toml. You can wrap the `io::Error`s that occur with additional context 107 | about what operation has failed: 108 | 109 | ```rust 110 | use failure::ResultExt; 111 | 112 | let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?; 113 | file.read_to_end(&buffer).context("Could not read Cargo.toml")?; 114 | ``` 115 | 116 | The `Context` object also has a constructor that does not take an underlying 117 | error, allowing you to create ad hoc Context errors alongside those created by 118 | applying the `context` method to an underlying error. 119 | 120 | ## Backwards compatibility 121 | 122 | We've taken several steps to make transitioning from `std::error` to `failure` as 123 | painless as possible. 124 | 125 | First, there is a blanket implementation of `Fail` for all types that implement 126 | `std::error::Error`, as long as they are `Send + Sync + 'static`. If you are 127 | dealing with a library that hasn't shifted to `Fail`, it is automatically 128 | compatible with `failure` already. 129 | 130 | Second, `Fail` contains a method called `compat`, which produces a type that 131 | implements `std::error::Error`. If you have a type that implements `Fail`, but 132 | not the older `Error` trait, you can call `compat` to get a type that does 133 | implement that trait (for example, if you need to return a `Box`). 134 | 135 | The biggest hole in our backwards compatibility story is that you cannot 136 | implement `std::error::Error` and also override the backtrace and cause methods 137 | on `Fail`. We intend to enable this with specialization when it becomes stable. 138 | 139 | [derive-docs]: https://boats.gitlab.io/failure/derive-fail.html 140 | [stderror]: https://doc.rust-lang.org/std/error/trait.Error.html 141 | [backtrace-crate]: http://alexcrichton.com/backtrace-rs 142 | -------------------------------------------------------------------------------- /book/src/guidance.md: -------------------------------------------------------------------------------- 1 | # Patterns & Guidance 2 | 3 | failure is not a "one size fits all" approach to error management. There are 4 | multiple patterns that emerge from the API this library provides, and users 5 | need to determine which pattern makes sense for them. This section documents 6 | some patterns and how users might use them. 7 | 8 | In brief, these are the patterns documented here: 9 | 10 | - **[Strings as errors](./error-msg.html):** Using strings as your error 11 | type. Good for prototyping. 12 | - **[A Custom Fail type](./custom-fail.html):** Defining a custom type to be 13 | your error type. Good for APIs where you control all or more of the 14 | possible failures. 15 | - **[Using the Error type](./use-error.html):** Using the Error type to pull 16 | together multiple failures of different types. Good for applications and 17 | APIs that know the error won't be inspected much more. 18 | - **[An Error and ErrorKind pair](./error-errorkind.html):** Using both a 19 | custom error type and an ErrorKind enum to create a very robust error 20 | type. Good for public APIs in large crates. 21 | 22 | (Though each of these items identifies a use case which this pattern would be 23 | good for, in truth each of them can be applied in various contexts. Its up to 24 | you to decide what makes the most sense for your particular use case.) 25 | -------------------------------------------------------------------------------- /book/src/howto.md: -------------------------------------------------------------------------------- 1 | # How to use failure 2 | 3 | This section of the documentation is about how the APIs exposed in failure can 4 | be used. It is organized around the major APIs of failure: 5 | 6 | - **[The Fail trait](./fail.html):** The primary abstraction provided by failure. 7 | - **[Deriving Fail](./derive-fail.html):** A custom derive for the Fail trait. 8 | - **[The Error type](./error.html):** A convenient wrapper around any Fail type. 9 | -------------------------------------------------------------------------------- /book/src/intro.md: -------------------------------------------------------------------------------- 1 | # failure 2 | 3 | This is the documentation for the failure crate, which provides a system for 4 | creating and managing errors in Rust. Additional documentation is found here: 5 | 6 | * [API documentation][api] 7 | * [failure source code][repo] 8 | * [failure_derive source code][derive-repo] 9 | 10 | [api]: https://boats.gitlab.io/failure/doc/failure 11 | [repo]: https://github.com/withoutboats/failure 12 | [derive-repo]: https://github.com/withoutboats/failure_derive 13 | 14 | ```rust 15 | extern crate serde; 16 | extern crate toml; 17 | 18 | #[macro_use] extern crate failure; 19 | #[macro_use] extern crate serde_derive; 20 | 21 | use std::collections::HashMap; 22 | use std::path::PathBuf; 23 | use std::str::FromStr; 24 | 25 | use failure::Error; 26 | 27 | // This is a new error type that you've created. It represents the ways a 28 | // toolchain could be invalid. 29 | // 30 | // The custom derive for Fail derives an impl of both Fail and Display. 31 | // We don't do any other magic like creating new types. 32 | #[derive(Debug, Fail)] 33 | enum ToolchainError { 34 | #[fail(display = "invalid toolchain name: {}", name)] 35 | InvalidToolchainName { 36 | name: String, 37 | }, 38 | #[fail(display = "unknown toolchain version: {}", version)] 39 | UnknownToolchainVersion { 40 | version: String, 41 | } 42 | } 43 | 44 | pub struct ToolchainId { 45 | // ... etc 46 | } 47 | 48 | impl FromStr for ToolchainId { 49 | type Err = ToolchainError; 50 | 51 | fn from_str(s: &str) -> Result { 52 | // ... etc 53 | } 54 | } 55 | 56 | pub type Toolchains = HashMap; 57 | 58 | // This opens a toml file containing associations between ToolchainIds and 59 | // Paths (the roots of those toolchains). 60 | // 61 | // This could encounter an io Error, a toml parsing error, or a ToolchainError, 62 | // all of them will be thrown into the special Error type 63 | pub fn read_toolchains(path: PathBuf) -> Result 64 | { 65 | use std::fs::File; 66 | use std::io::Read; 67 | 68 | let mut string = String::new(); 69 | File::open(path)?.read_to_string(&mut string)?; 70 | 71 | let toml: HashMap = toml::from_str(&string)?; 72 | 73 | let toolchains = toml.iter().map(|(key, path)| { 74 | let toolchain_id = key.parse()?; 75 | Ok((toolchain_id, path)) 76 | }).collect::>()?; 77 | 78 | Ok(toolchains) 79 | } 80 | -------------------------------------------------------------------------------- /book/src/use-error.md: -------------------------------------------------------------------------------- 1 | # Use the `Error` type 2 | 3 | This pattern is a way to manage errors when you have multiple kinds of failure 4 | that could occur during a single function. It has several distinct advantages: 5 | 6 | 1. You can start using it without defining any of your own failure types. 7 | 2. All types that implement `Fail` can be thrown into the `Error` type using 8 | the `?` operator. 9 | 3. As you start adding new dependencies with their own failure types, you can 10 | start throwing them without making a breaking change. 11 | 12 | To use this pattern, all you need to do is return `Result<_, Error>` from your 13 | functions: 14 | 15 | ```rust 16 | use std::io; 17 | use std::io::BufRead; 18 | 19 | use failure::Error; 20 | use failure::err_msg; 21 | 22 | fn my_function() -> Result<(), Error> { 23 | let stdin = io::stdin(); 24 | 25 | for line in stdin.lock().lines() { 26 | let line = line?; 27 | 28 | if line.chars().all(|c| c.is_whitespace()) { 29 | break 30 | } 31 | 32 | if !line.starts_with("$") { 33 | return Err(format_err!("Input did not begin with `$`")); 34 | } 35 | 36 | println!("{}", &line[1..]); 37 | } 38 | 39 | Ok(()) 40 | } 41 | ``` 42 | 43 | ## When might you use this pattern? 44 | 45 | This pattern is very effective when you know you will usually not need to 46 | destructure the error this function returns. For example: 47 | 48 | - When prototyping. 49 | - When you know you are going to log this error, or display it to the user, 50 | either all of the time or nearly all of the time. 51 | - When it would be impractical for this API to report more custom context for 52 | the error (e.g. because it is a trait that doesn't want to add a new Error 53 | associated type). 54 | 55 | ## Caveats on this pattern 56 | 57 | There are two primary downsides to this pattern: 58 | 59 | - The `Error` type allocates. There are cases where this would be too 60 | expensive. In those cases you should use a [custom failure][custom-fail]. 61 | - You cannot recover more information about this error without downcasting. If 62 | your API needs to express more contextual information about the error, use 63 | the [Error and ErrorKind][error-errorkind] pattern. 64 | 65 | [custom-fail]: ./custom-fail.html 66 | [error-errorkind]: ./error-errorkind.html 67 | -------------------------------------------------------------------------------- /build-docs.sh: -------------------------------------------------------------------------------- 1 | mkdir public 2 | cargo doc --no-deps 3 | cargo install mdbook --no-default-features 4 | mdbook build ./book 5 | cp -r ./target/doc/ ./public 6 | cp -r ./book/book/* ./public 7 | find $PWD/public | grep "\.html\$" 8 | -------------------------------------------------------------------------------- /failure-0.1.X/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "Experimental error handling abstraction." 4 | documentation = "https://docs.rs/failure" 5 | homepage = "https://boats.gitlab.io/failure" 6 | license = "MIT OR Apache-2.0" 7 | name = "failure" 8 | repository = "https://github.com/withoutboats/failure" 9 | version = "0.1.2" 10 | 11 | [dependencies.failure_compat_shim] 12 | version = "1.0.0" 13 | path = "../failure_compat_shim" 14 | default-features = false 15 | 16 | [dependencies.failure_derive] 17 | optional = true 18 | version = "0.1.2" 19 | path = "./failure_derive" 20 | 21 | [features] 22 | default = ["std", "derive"] 23 | backtrace = ["failure_compat_shim/backtrace"] 24 | std = ["backtrace", "failure_compat_shim/std"] 25 | derive = ["failure_derive", "failure_compat_shim/derive"] 26 | 27 | [[example]] 28 | name = "bail_ensure" 29 | path = "./examples/bail_ensure.rs" 30 | required-features = ["std"] 31 | -------------------------------------------------------------------------------- /failure-0.1.X/examples/bail_ensure.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Error; 5 | 6 | fn bailer() -> Result<(), Error> { 7 | // bail!("ruh roh"); 8 | bail!("ruh {}", "roh"); 9 | } 10 | 11 | fn ensures() -> Result<(), Error> { 12 | ensure!(true, "true is false"); 13 | ensure!(false, "false is false"); 14 | Ok(()) 15 | } 16 | 17 | fn main() { 18 | match bailer() { 19 | Ok(_) => println!("ok"), 20 | Err(e) => println!("{}", e), 21 | } 22 | match ensures() { 23 | Ok(_) => println!("ok"), 24 | Err(e) => println!("{}", e), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.18.0 4 | - stable 5 | - beta 6 | - nightly 7 | cache: cargo 8 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "derives for the failure crate" 4 | license = "MIT OR Apache-2.0" 5 | name = "failure_derive" 6 | repository = "https://github.com/withoutboats/failure_derive" 7 | homepage = "https://boats.gitlab.io/failure" 8 | documentation = "https://boats.gitlab.io/failure" 9 | version = "0.1.2" 10 | 11 | [dependencies] 12 | quote = "0.3.15" 13 | syn = "0.11.11" 14 | synstructure = "0.6.0" 15 | 16 | [dev-dependencies.failure] 17 | version = "0.1.0" 18 | 19 | [dev-dependencies.display_derive] 20 | git = "https://github.com/withoutboats/display_derive" 21 | 22 | [lib] 23 | proc-macro = true 24 | 25 | [features] 26 | default = ["std"] 27 | std = [] 28 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | extern crate syn; 3 | 4 | #[macro_use] extern crate synstructure; 5 | #[macro_use] extern crate quote; 6 | 7 | use std::io::{self, Write}; 8 | 9 | decl_derive!([Fail, attributes(fail, cause)] => fail_derive); 10 | 11 | fn fail_derive(s: synstructure::Structure) -> quote::Tokens { 12 | let cause_body = s.each_variant(|v| { 13 | if let Some(cause) = v.bindings().iter().find(is_cause) { 14 | quote!(return Some(#cause)) 15 | } else { 16 | quote!(return None) 17 | } 18 | }); 19 | 20 | let bt_body = s.each_variant(|v| { 21 | if let Some(bi) = v.bindings().iter().find(is_backtrace) { 22 | quote!(return Some(#bi)) 23 | } else { 24 | quote!(return None) 25 | } 26 | }); 27 | 28 | #[cfg(feature = "std")] 29 | let fail = s.bound_impl("::failure::Fail", quote! { 30 | #[allow(unreachable_code)] 31 | fn cause(&self) -> ::std::option::Option<&::failure::Fail> { 32 | match *self { #cause_body } 33 | None 34 | } 35 | 36 | #[allow(unreachable_code)] 37 | fn backtrace(&self) -> ::std::option::Option<&::failure::Backtrace> { 38 | match *self { #bt_body } 39 | None 40 | } 41 | }); 42 | 43 | #[cfg(not(feature = "std"))] 44 | let fail = s.bound_impl("::failure::Fail", quote! { 45 | #[allow(unreachable_code)] 46 | fn cause(&self) -> ::core::option::Option<&::failure::Fail> { 47 | match *self { #cause_body } 48 | None 49 | } 50 | 51 | #[allow(unreachable_code)] 52 | fn backtrace(&self) -> ::core::option::Option<&::failure::Backtrace> { 53 | match *self { #bt_body } 54 | None 55 | } 56 | }); 57 | 58 | #[cfg(feature = "std")] 59 | let display = display_body(&s).map(|display_body| { 60 | s.bound_impl("::std::fmt::Display", quote! { 61 | #[allow(unreachable_code)] 62 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 63 | match *self { #display_body } 64 | write!(f, "An error has occurred.") 65 | } 66 | }) 67 | }); 68 | 69 | #[cfg(not(feature = "std"))] 70 | let display = display_body(&s).map(|display_body| { 71 | s.bound_impl("::core::fmt::Display", quote! { 72 | #[allow(unreachable_code)] 73 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 74 | match *self { #display_body } 75 | write!(f, "An error has occurred.") 76 | } 77 | }) 78 | }); 79 | 80 | quote! { 81 | #fail 82 | #display 83 | } 84 | } 85 | 86 | fn display_body(s: &synstructure::Structure) -> Option { 87 | let mut msgs = s.variants().iter().map(|v| find_error_msg(&v.ast().attrs)); 88 | if msgs.all(|msg| msg.is_none()) { return None; } 89 | 90 | Some(s.each_variant(|v| { 91 | let msg = find_error_msg(&v.ast().attrs).expect("All variants must have display attribute."); 92 | if msg.is_empty() { 93 | panic!("Expected at least one argument to fail attribute"); 94 | } 95 | 96 | let s = match msg[0] { 97 | syn::NestedMetaItem::MetaItem(syn::MetaItem::NameValue(ref i, ref lit)) if i == "display" => { 98 | lit.clone() 99 | } 100 | _ => panic!("Fail attribute must begin `display = \"\"` to control the Display message."), 101 | }; 102 | let args = msg[1..].iter().map(|arg| match *arg { 103 | syn::NestedMetaItem::Literal(syn::Lit::Int(i, _)) => { 104 | let bi = &v.bindings()[i as usize]; 105 | quote!(#bi) 106 | } 107 | syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref id)) => { 108 | if id.as_ref().starts_with("_") { 109 | if let Ok(idx) = id.as_ref()[1..].parse::() { 110 | let bi = &v.bindings()[idx]; 111 | return quote!(#bi) 112 | } 113 | } 114 | for bi in v.bindings() { 115 | if bi.ast().ident.as_ref() == Some(id) { 116 | return quote!(#bi); 117 | } 118 | } 119 | panic!("Couldn't find a field with this name!"); 120 | } 121 | _ => panic!("Invalid argument to fail attribute!"), 122 | }); 123 | 124 | quote! { 125 | return write!(f, #s #(, #args)*) 126 | } 127 | })) 128 | } 129 | 130 | fn find_error_msg(attrs: &[syn::Attribute]) -> Option<&[syn::NestedMetaItem]> { 131 | let mut error_msg = None; 132 | for attr in attrs { 133 | if attr.name() == "fail" { 134 | if error_msg.is_some() { 135 | panic!("Cannot have two display attributes") 136 | } else { 137 | if let syn::MetaItem::List(_, ref list) = attr.value { 138 | error_msg = Some(&list[..]); 139 | } else { 140 | panic!("fail attribute must take a list in parantheses") 141 | } 142 | } 143 | } 144 | } 145 | error_msg 146 | } 147 | 148 | fn is_backtrace(bi: &&synstructure::BindingInfo) -> bool { 149 | match bi.ast().ty { 150 | syn::Ty::Path(None, syn::Path { segments: ref path, .. }) => { 151 | path.last().map_or(false, |s| s.ident == "Backtrace" && s.parameters.is_empty()) 152 | } 153 | _ => false 154 | } 155 | } 156 | 157 | fn is_cause(bi: &&synstructure::BindingInfo) -> bool { 158 | let mut found_cause = false; 159 | for attr in &bi.ast().attrs { 160 | if attr.name() == "cause" { 161 | if found_cause { panic!("Cannot have two `cause` attributes"); } 162 | writeln!( 163 | io::stderr(), 164 | "WARNING: failure's `#[cause]` attribute is deprecated. Use `#[fail(cause)]` instead." 165 | ).unwrap(); 166 | found_cause = true; 167 | } 168 | if attr.name() == "fail" { 169 | if let syn::MetaItem::List(_, ref list) = attr.value { 170 | if let Some(&syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref word))) = list.get(0) { 171 | if word == "cause" { 172 | if found_cause { panic!("Cannot have two `cause` attributes"); } 173 | found_cause = true; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | found_cause 180 | } 181 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/tests/backtrace.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | 4 | use failure::{Fail, Backtrace}; 5 | 6 | #[derive(Fail, Debug)] 7 | #[fail(display = "Error code: {}", code)] 8 | struct BacktraceError { 9 | backtrace: Backtrace, 10 | code: u32, 11 | } 12 | 13 | #[test] 14 | fn backtrace_error() { 15 | let err = BacktraceError { backtrace: Backtrace::new(), code: 7 }; 16 | let s = format!("{}", err); 17 | assert_eq!(&s[..], "Error code: 7"); 18 | assert!(err.backtrace().is_some()); 19 | } 20 | 21 | #[derive(Fail, Debug)] 22 | #[fail(display = "An error has occurred.")] 23 | struct BacktraceTupleError(Backtrace); 24 | 25 | #[test] 26 | fn backtrace_tuple_error() { 27 | let err = BacktraceTupleError(Backtrace::new()); 28 | let s = format!("{}", err); 29 | assert_eq!(&s[..], "An error has occurred."); 30 | assert!(err.backtrace().is_some()); 31 | } 32 | 33 | #[derive(Fail, Debug)] 34 | enum BacktraceEnumError { 35 | #[fail(display = "Error code: {}", code)] 36 | StructVariant { 37 | code: i32, 38 | backtrace: Backtrace, 39 | }, 40 | #[fail(display = "Error: {}", _0)] 41 | TupleVariant(&'static str, Backtrace), 42 | #[fail(display = "An error has occurred.")] 43 | UnitVariant, 44 | } 45 | 46 | #[test] 47 | fn backtrace_enum_error() { 48 | let err = BacktraceEnumError::StructVariant { code: 2, backtrace: Backtrace::new() }; 49 | let s = format!("{}", err); 50 | assert_eq!(&s[..], "Error code: 2"); 51 | assert!(err.backtrace().is_some()); 52 | let err = BacktraceEnumError::TupleVariant("foobar", Backtrace::new()); 53 | let s = format!("{}", err); 54 | assert_eq!(&s[..], "Error: foobar"); 55 | assert!(err.backtrace().is_some()); 56 | let err = BacktraceEnumError::UnitVariant; 57 | let s = format!("{}", err); 58 | assert_eq!(&s[..], "An error has occurred."); 59 | assert!(err.backtrace().is_none()); 60 | } 61 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/tests/external_display_derive.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | #[macro_use] extern crate display_derive; 4 | 5 | use std::io; 6 | 7 | use failure::Fail; 8 | 9 | #[derive(Debug, Fail, Display)] 10 | #[display(fmt = "An error occurred.")] 11 | struct Foo(#[fail(cause)] io::Error); 12 | 13 | #[test] 14 | fn external_display_derive() { 15 | let foo = Foo(io::Error::from_raw_os_error(98)); 16 | assert!(foo.cause().is_some()); 17 | assert_eq!(&format!("{}", foo)[..], "An error occurred."); 18 | } 19 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/tests/no_derive_display.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | 4 | use std::fmt::{self, Display}; 5 | use failure::Fail; 6 | 7 | #[derive(Debug, Fail)] 8 | struct Foo; 9 | 10 | impl Display for Foo { 11 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 12 | f.write_str("An error occurred.") 13 | } 14 | } 15 | 16 | #[test] 17 | fn handwritten_display() { 18 | assert!(Foo.cause().is_none()); 19 | assert_eq!(&format!("{}", Foo)[..], "An error occurred."); 20 | } 21 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/tests/tests.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | 4 | #[derive(Fail, Debug)] 5 | #[fail(display = "An error has occurred.")] 6 | struct UnitError; 7 | 8 | #[test] 9 | fn unit_struct() { 10 | let s = format!("{}", UnitError); 11 | assert_eq!(&s[..], "An error has occurred."); 12 | } 13 | 14 | #[derive(Fail, Debug)] 15 | #[fail(display = "Error code: {}", code)] 16 | struct RecordError { 17 | code: u32, 18 | } 19 | 20 | #[test] 21 | fn record_struct() { 22 | let s = format!("{}", RecordError { code: 0 }); 23 | assert_eq!(&s[..], "Error code: 0"); 24 | } 25 | 26 | #[derive(Fail, Debug)] 27 | #[fail(display = "Error code: {}", _0)] 28 | struct TupleError(i32); 29 | 30 | #[test] 31 | fn tuple_struct() { 32 | let s = format!("{}", TupleError(2)); 33 | assert_eq!(&s[..], "Error code: 2"); 34 | } 35 | 36 | #[derive(Fail, Debug)] 37 | enum EnumError { 38 | #[fail(display = "Error code: {}", code)] 39 | StructVariant { 40 | code: i32, 41 | }, 42 | #[fail(display = "Error: {}", _0)] 43 | TupleVariant(&'static str), 44 | #[fail(display = "An error has occurred.")] 45 | UnitVariant, 46 | } 47 | 48 | #[test] 49 | fn enum_error() { 50 | let s = format!("{}", EnumError::StructVariant { code: 2 }); 51 | assert_eq!(&s[..], "Error code: 2"); 52 | let s = format!("{}", EnumError::TupleVariant("foobar")); 53 | assert_eq!(&s[..], "Error: foobar"); 54 | let s = format!("{}", EnumError::UnitVariant); 55 | assert_eq!(&s[..], "An error has occurred."); 56 | } 57 | -------------------------------------------------------------------------------- /failure-0.1.X/failure_derive/tests/wraps.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | 4 | use std::io; 5 | use std::fmt; 6 | 7 | use failure::{Backtrace, Fail}; 8 | 9 | #[derive(Fail, Debug)] 10 | #[fail(display = "An error has occurred: {}", inner)] 11 | struct WrapError { 12 | #[fail(cause)] inner: io::Error, 13 | } 14 | 15 | #[test] 16 | fn wrap_error() { 17 | let inner = io::Error::from_raw_os_error(98); 18 | let err = WrapError { inner }; 19 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 20 | } 21 | 22 | #[derive(Fail, Debug)] 23 | #[fail(display = "An error has occurred: {}", _0)] 24 | struct WrapTupleError(#[fail(cause)] io::Error); 25 | 26 | #[test] 27 | fn wrap_tuple_error() { 28 | let io_error = io::Error::from_raw_os_error(98); 29 | let err: WrapTupleError = WrapTupleError(io_error); 30 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 31 | } 32 | 33 | #[derive(Fail, Debug)] 34 | #[fail(display = "An error has occurred: {}", inner)] 35 | struct WrapBacktraceError { 36 | #[fail(cause)] inner: io::Error, 37 | backtrace: Backtrace, 38 | } 39 | 40 | #[test] 41 | fn wrap_backtrace_error() { 42 | let inner = io::Error::from_raw_os_error(98); 43 | let err: WrapBacktraceError = WrapBacktraceError { inner, backtrace: Backtrace::new() }; 44 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 45 | assert!(err.backtrace().is_some()); 46 | } 47 | 48 | #[derive(Fail, Debug)] 49 | enum WrapEnumError { 50 | #[fail(display = "An error has occurred: {}", _0)] 51 | Io(#[fail(cause)] io::Error), 52 | #[fail(display = "An error has occurred: {}", inner)] 53 | Fmt { 54 | #[fail(cause)] inner: fmt::Error, 55 | backtrace: Backtrace, 56 | }, 57 | } 58 | 59 | #[test] 60 | fn wrap_enum_error() { 61 | let io_error = io::Error::from_raw_os_error(98); 62 | let err: WrapEnumError = WrapEnumError::Io(io_error); 63 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 64 | assert!(err.backtrace().is_none()); 65 | let fmt_error = fmt::Error::default(); 66 | let err: WrapEnumError = WrapEnumError::Fmt { inner: fmt_error, backtrace: Backtrace::new() }; 67 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 68 | assert!(err.backtrace().is_some()); 69 | } 70 | -------------------------------------------------------------------------------- /failure-0.1.X/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An experimental new error-handling library. Guide-style introduction 2 | //! is available [here](https://boats.gitlab.io/failure/). 3 | //! 4 | //! The primary items exported by this library are: 5 | //! 6 | //! - `Fail`: a new trait for custom error types in Rust. 7 | //! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them 8 | //! at higher levels. 9 | //! 10 | //! As a general rule, library authors should create their own error types and 11 | //! implement `Fail` for them, whereas application authors should primarily 12 | //! deal with the `Error` type. There are exceptions to this rule, though, in 13 | //! both directions, and users should do whatever seems most appropriate to 14 | //! their situation. 15 | #![cfg_attr(not(feature = "std"), no_std)] 16 | #![deny(missing_docs)] 17 | 18 | macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } 19 | 20 | extern crate failure_compat_shim as failure; 21 | 22 | #[cfg(feature = "derive")] 23 | #[allow(unused_imports)] 24 | #[macro_use] 25 | extern crate failure_derive; 26 | 27 | #[cfg(feature = "derive")] 28 | #[doc(hidden)] 29 | pub use failure_derive::*; 30 | 31 | pub use failure::{Fail, Causes, Backtrace, Context, Compat, ResultExt}; 32 | 33 | with_std! { 34 | extern crate core; 35 | 36 | pub use failure::{Error, SyncFailure, err_msg}; 37 | 38 | mod macros; 39 | } 40 | -------------------------------------------------------------------------------- /failure-0.1.X/src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Exits a function early with an `Error`. 2 | /// 3 | /// The `bail!` macro provides an easy way to exit a function. `bail!(X)` is 4 | /// equivalent to writing: 5 | /// 6 | /// ```rust,ignore 7 | /// return Err(format_err!(X)) 8 | /// ``` 9 | #[macro_export] 10 | macro_rules! bail { 11 | ($e:expr) => { 12 | return Err($crate::err_msg($e)); 13 | }; 14 | ($fmt:expr, $($arg:tt)+) => { 15 | return Err($crate::err_msg(format!($fmt, $($arg)+))); 16 | }; 17 | } 18 | 19 | /// Exits a function early with an `Error` if the condition is not satisfied. 20 | /// 21 | /// Similar to `assert!`, `ensure!` takes a condition and exits the function 22 | /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`, 23 | /// it does not panic. 24 | #[macro_export] 25 | macro_rules! ensure { 26 | ($cond:expr, $e:expr) => { 27 | if !($cond) { 28 | bail!($e); 29 | } 30 | }; 31 | ($cond:expr, $fmt:expr, $($arg:tt)+) => { 32 | if !($cond) { 33 | bail!($fmt, $($arg)+); 34 | } 35 | }; 36 | } 37 | 38 | /// Constructs an `Error` using the standard string interpolation syntax. 39 | /// 40 | /// ```rust 41 | /// #[macro_use] extern crate failure; 42 | /// 43 | /// fn main() { 44 | /// let code = 101; 45 | /// let err = format_err!("Error code: {}", code); 46 | /// } 47 | /// ``` 48 | #[macro_export] 49 | macro_rules! format_err { 50 | ($($arg:tt)*) => { $crate::err_msg(format!($($arg)*)) } 51 | } 52 | -------------------------------------------------------------------------------- /failure-1.X/.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | **/Cargo.lock 4 | public 5 | book/book 6 | -------------------------------------------------------------------------------- /failure-1.X/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "rust:latest" 2 | 3 | pages: 4 | script: 5 | - sh ./build-docs.sh 6 | artifacts: 7 | paths: 8 | - public 9 | only: 10 | - master 11 | -------------------------------------------------------------------------------- /failure-1.X/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.18.0 4 | - stable 5 | - beta 6 | - nightly 7 | cache: cargo 8 | script: 9 | - cargo test 10 | - cargo test --no-default-features 11 | -------------------------------------------------------------------------------- /failure-1.X/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "Experimental error handling abstraction." 4 | documentation = "https://docs.rs/failure" 5 | homepage = "https://boats.gitlab.io/failure" 6 | license = "MIT OR Apache-2.0" 7 | name = "failure" 8 | repository = "https://github.com/withoutboats/failure" 9 | version = "1.0.0" 10 | 11 | [dependencies.failure_derive] 12 | optional = true 13 | version = "1.0.0" 14 | path = "./failure_derive" 15 | 16 | [dependencies.display_derive] 17 | optional = true 18 | git = "https://github.com/withoutboats/display_derive" 19 | 20 | [dependencies.backtrace] 21 | optional = true 22 | version = "0.3.3" 23 | 24 | [features] 25 | default = ["std", "derive"] 26 | small-error = ["std"] 27 | std = [] 28 | derive = ["failure_derive", "display_derive"] 29 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.18.0 4 | - stable 5 | - beta 6 | - nightly 7 | cache: cargo 8 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "derives for the failure crate" 4 | license = "MIT OR Apache-2.0" 5 | name = "failure_derive" 6 | repository = "https://github.com/withoutboats/failure_derive" 7 | homepage = "https://boats.gitlab.io/failure" 8 | documentation = "https://boats.gitlab.io/failure" 9 | version = "1.0.0" 10 | 11 | [dependencies] 12 | quote = "0.3.15" 13 | syn = "0.11.11" 14 | synstructure = "0.6.0" 15 | 16 | [dev-dependencies.failure] 17 | version = "0.1.0" 18 | 19 | [dev-dependencies.display_derive] 20 | git = "https://github.com/withoutboats/display_derive" 21 | 22 | [lib] 23 | proc-macro = true 24 | 25 | [features] 26 | default = ["std"] 27 | std = [] 28 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | extern crate syn; 3 | 4 | #[macro_use] extern crate synstructure; 5 | #[macro_use] extern crate quote; 6 | 7 | decl_derive!([Fail, attributes(fail, cause)] => fail_derive); 8 | 9 | fn fail_derive(s: synstructure::Structure) -> quote::Tokens { 10 | let cause_body = s.each_variant(|v| { 11 | if let Some(cause) = v.bindings().iter().find(is_cause) { 12 | quote!(return Some(#cause)) 13 | } else { 14 | quote!(return None) 15 | } 16 | }); 17 | 18 | let bt_body = s.each_variant(|v| { 19 | if let Some(bi) = v.bindings().iter().find(is_backtrace) { 20 | quote!(return Some(#bi)) 21 | } else { 22 | quote!(return None) 23 | } 24 | }); 25 | 26 | #[cfg(feature = "std")] 27 | let fail = s.bound_impl("::failure::Fail", quote! { 28 | #[allow(unreachable_code)] 29 | fn cause(&self) -> ::std::option::Option<&::failure::Fail> { 30 | match *self { #cause_body } 31 | None 32 | } 33 | 34 | #[allow(unreachable_code)] 35 | fn backtrace(&self) -> ::std::option::Option<&::failure::Backtrace> { 36 | match *self { #bt_body } 37 | None 38 | } 39 | }); 40 | 41 | #[cfg(not(feature = "std"))] 42 | let fail = s.bound_impl("::failure::Fail", quote! { 43 | #[allow(unreachable_code)] 44 | fn cause(&self) -> ::core::option::Option<&::failure::Fail> { 45 | match *self { #cause_body } 46 | None 47 | } 48 | 49 | #[allow(unreachable_code)] 50 | fn backtrace(&self) -> ::core::option::Option<&::failure::Backtrace> { 51 | match *self { #bt_body } 52 | None 53 | } 54 | }); 55 | 56 | quote! { 57 | #fail 58 | } 59 | } 60 | 61 | fn is_backtrace(bi: &&synstructure::BindingInfo) -> bool { 62 | match bi.ast().ty { 63 | syn::Ty::Path(None, syn::Path { segments: ref path, .. }) => { 64 | path.last().map_or(false, |s| s.ident == "Backtrace" && s.parameters.is_empty()) 65 | } 66 | _ => false 67 | } 68 | } 69 | 70 | fn is_cause(bi: &&synstructure::BindingInfo) -> bool { 71 | let mut found_cause = false; 72 | for attr in &bi.ast().attrs { 73 | if attr.name() == "fail" { 74 | if let syn::MetaItem::List(_, ref list) = attr.value { 75 | if let Some(&syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref word))) = list.get(0) { 76 | if word == "cause" { 77 | if found_cause { panic!("Cannot have two `cause` attributes"); } 78 | found_cause = true; 79 | } 80 | } 81 | } 82 | } 83 | } 84 | found_cause 85 | } 86 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/tests/backtrace.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | #[macro_use] extern crate display_derive; 4 | 5 | use failure::{Fail, Backtrace}; 6 | 7 | #[derive(Fail, Debug, Display)] 8 | #[display(fmt = "Error code: {}", code)] 9 | struct BacktraceError { 10 | backtrace: Backtrace, 11 | code: u32, 12 | } 13 | 14 | #[test] 15 | fn backtrace_error() { 16 | let err = BacktraceError { backtrace: Backtrace::new(), code: 7 }; 17 | let s = format!("{}", err); 18 | assert_eq!(&s[..], "Error code: 7"); 19 | assert!(err.backtrace().is_some()); 20 | } 21 | 22 | #[derive(Fail, Debug, Display)] 23 | #[display(fmt = "An error has occurred.")] 24 | struct BacktraceTupleError(Backtrace); 25 | 26 | #[test] 27 | fn backtrace_tuple_error() { 28 | let err = BacktraceTupleError(Backtrace::new()); 29 | let s = format!("{}", err); 30 | assert_eq!(&s[..], "An error has occurred."); 31 | assert!(err.backtrace().is_some()); 32 | } 33 | 34 | #[derive(Fail, Debug, Display)] 35 | enum BacktraceEnumError { 36 | #[display(fmt = "Error code: {}", code)] 37 | StructVariant { 38 | code: i32, 39 | backtrace: Backtrace, 40 | }, 41 | #[display(fmt = "Error: {}", _0)] 42 | TupleVariant(&'static str, Backtrace), 43 | #[display(fmt = "An error has occurred.")] 44 | UnitVariant, 45 | } 46 | 47 | #[test] 48 | fn backtrace_enum_error() { 49 | let err = BacktraceEnumError::StructVariant { code: 2, backtrace: Backtrace::new() }; 50 | let s = format!("{}", err); 51 | assert_eq!(&s[..], "Error code: 2"); 52 | assert!(err.backtrace().is_some()); 53 | let err = BacktraceEnumError::TupleVariant("foobar", Backtrace::new()); 54 | let s = format!("{}", err); 55 | assert_eq!(&s[..], "Error: foobar"); 56 | assert!(err.backtrace().is_some()); 57 | let err = BacktraceEnumError::UnitVariant; 58 | let s = format!("{}", err); 59 | assert_eq!(&s[..], "An error has occurred."); 60 | assert!(err.backtrace().is_none()); 61 | } 62 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/tests/no_derive_display.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | 4 | use std::fmt::{self, Display}; 5 | use failure::Fail; 6 | 7 | #[derive(Debug, Fail)] 8 | struct Foo; 9 | 10 | impl Display for Foo { 11 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 12 | f.write_str("An error occurred.") 13 | } 14 | } 15 | 16 | #[test] 17 | fn handwritten_display() { 18 | assert!(Foo.cause().is_none()); 19 | assert_eq!(&format!("{}", Foo)[..], "An error occurred."); 20 | } 21 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/tests/tests.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | #[macro_use] extern crate display_derive; 4 | 5 | #[derive(Fail, Debug, Display)] 6 | #[display(fmt = "An error has occurred.")] 7 | struct UnitError; 8 | 9 | #[test] 10 | fn unit_struct() { 11 | let s = format!("{}", UnitError); 12 | assert_eq!(&s[..], "An error has occurred."); 13 | } 14 | 15 | #[derive(Fail, Debug, Display)] 16 | #[display(fmt = "Error code: {}", code)] 17 | struct RecordError { 18 | code: u32, 19 | } 20 | 21 | #[test] 22 | fn record_struct() { 23 | let s = format!("{}", RecordError { code: 0 }); 24 | assert_eq!(&s[..], "Error code: 0"); 25 | } 26 | 27 | #[derive(Fail, Debug, Display)] 28 | #[display(fmt = "Error code: {}", _0)] 29 | struct TupleError(i32); 30 | 31 | #[test] 32 | fn tuple_struct() { 33 | let s = format!("{}", TupleError(2)); 34 | assert_eq!(&s[..], "Error code: 2"); 35 | } 36 | 37 | #[derive(Fail, Debug, Display)] 38 | enum EnumError { 39 | #[display(fmt = "Error code: {}", code)] 40 | StructVariant { 41 | code: i32, 42 | }, 43 | #[display(fmt = "Error: {}", _0)] 44 | TupleVariant(&'static str), 45 | #[display(fmt = "An error has occurred.")] 46 | UnitVariant, 47 | } 48 | 49 | #[test] 50 | fn enum_error() { 51 | let s = format!("{}", EnumError::StructVariant { code: 2 }); 52 | assert_eq!(&s[..], "Error code: 2"); 53 | let s = format!("{}", EnumError::TupleVariant("foobar")); 54 | assert_eq!(&s[..], "Error: foobar"); 55 | let s = format!("{}", EnumError::UnitVariant); 56 | assert_eq!(&s[..], "An error has occurred."); 57 | } 58 | -------------------------------------------------------------------------------- /failure-1.X/failure_derive/tests/wraps.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] extern crate failure_derive; 3 | #[macro_use] extern crate display_derive; 4 | 5 | use std::io; 6 | use std::fmt; 7 | 8 | use failure::{Backtrace, Fail}; 9 | 10 | #[derive(Fail, Debug, Display)] 11 | #[display(fmt = "An error has occurred: {}", inner)] 12 | struct WrapError { 13 | #[fail(cause)] inner: io::Error, 14 | } 15 | 16 | #[test] 17 | fn wrap_error() { 18 | let inner = io::Error::from_raw_os_error(98); 19 | let err = WrapError { inner }; 20 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 21 | } 22 | 23 | #[derive(Fail, Debug, Display)] 24 | #[display(fmt = "An error has occurred: {}", _0)] 25 | struct WrapTupleError(#[fail(cause)] io::Error); 26 | 27 | #[test] 28 | fn wrap_tuple_error() { 29 | let io_error = io::Error::from_raw_os_error(98); 30 | let err: WrapTupleError = WrapTupleError(io_error); 31 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 32 | } 33 | 34 | #[derive(Fail, Debug, Display)] 35 | #[display(fmt = "An error has occurred: {}", inner)] 36 | struct WrapBacktraceError { 37 | #[fail(cause)] inner: io::Error, 38 | backtrace: Backtrace, 39 | } 40 | 41 | #[test] 42 | fn wrap_backtrace_error() { 43 | let inner = io::Error::from_raw_os_error(98); 44 | let err: WrapBacktraceError = WrapBacktraceError { inner, backtrace: Backtrace::new() }; 45 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 46 | assert!(err.backtrace().is_some()); 47 | } 48 | 49 | #[derive(Fail, Debug, Display)] 50 | enum WrapEnumError { 51 | #[display(fmt = "An error has occurred: {}", _0)] 52 | Io(#[fail(cause)] io::Error), 53 | #[display(fmt = "An error has occurred: {}", inner)] 54 | Fmt { 55 | #[fail(cause)] inner: fmt::Error, 56 | backtrace: Backtrace, 57 | }, 58 | } 59 | 60 | #[test] 61 | fn wrap_enum_error() { 62 | let io_error = io::Error::from_raw_os_error(98); 63 | let err: WrapEnumError = WrapEnumError::Io(io_error); 64 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 65 | assert!(err.backtrace().is_none()); 66 | let fmt_error = fmt::Error::default(); 67 | let err: WrapEnumError = WrapEnumError::Fmt { inner: fmt_error, backtrace: Backtrace::new() }; 68 | assert!(err.cause().and_then(|err| err.downcast_ref::()).is_some()); 69 | assert!(err.backtrace().is_some()); 70 | } 71 | -------------------------------------------------------------------------------- /failure-1.X/src/backtrace/internal.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::env; 3 | use std::ffi::OsString; 4 | use std::fmt; 5 | use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; 6 | use std::sync::Mutex; 7 | 8 | pub use super::backtrace::Backtrace; 9 | 10 | const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE"; 11 | const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE"; 12 | 13 | pub(super) struct InternalBacktrace { 14 | backtrace: Option, 15 | } 16 | 17 | struct MaybeResolved { 18 | resolved: Mutex, 19 | backtrace: UnsafeCell, 20 | } 21 | 22 | unsafe impl Send for MaybeResolved {} 23 | unsafe impl Sync for MaybeResolved {} 24 | 25 | impl InternalBacktrace { 26 | pub(super) fn new() -> InternalBacktrace { 27 | static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT; 28 | 29 | match ENABLED.load(Ordering::SeqCst) { 30 | 0 => { 31 | let enabled = is_backtrace_enabled(|var| env::var_os(var)); 32 | ENABLED.store(enabled as usize + 1, Ordering::SeqCst); 33 | if !enabled { 34 | return InternalBacktrace { backtrace: None } 35 | } 36 | } 37 | 1 => return InternalBacktrace { backtrace: None }, 38 | _ => {} 39 | } 40 | 41 | InternalBacktrace { 42 | backtrace: Some(MaybeResolved { 43 | resolved: Mutex::new(false), 44 | backtrace: UnsafeCell::new(Backtrace::new_unresolved()), 45 | }), 46 | } 47 | } 48 | 49 | pub(super) fn none() -> InternalBacktrace { 50 | InternalBacktrace { backtrace: None } 51 | } 52 | 53 | pub(super) fn as_backtrace(&self) -> Option<&Backtrace> { 54 | let bt = match self.backtrace { 55 | Some(ref bt) => bt, 56 | None => return None, 57 | }; 58 | let mut resolved = bt.resolved.lock().unwrap(); 59 | unsafe { 60 | if !*resolved { 61 | (*bt.backtrace.get()).resolve(); 62 | *resolved = true; 63 | } 64 | Some(&*bt.backtrace.get()) 65 | } 66 | } 67 | 68 | pub(super) fn is_none(&self) -> bool { 69 | self.backtrace.is_none() 70 | } 71 | } 72 | 73 | impl fmt::Debug for InternalBacktrace { 74 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 75 | f.debug_struct("InternalBacktrace") 76 | .field("backtrace", &self.as_backtrace()) 77 | .finish() 78 | } 79 | } 80 | 81 | fn is_backtrace_enabled Option>(get_var: F) -> bool { 82 | match get_var(FAILURE_BACKTRACE) { 83 | Some(ref val) if val != "0" => true, 84 | Some(ref val) if val == "0" => false, 85 | _ => match get_var(GENERAL_BACKTRACE) { 86 | Some(ref val) if val != "0" => true, 87 | _ => false, 88 | } 89 | } 90 | } 91 | 92 | #[cfg(test)] 93 | mod tests { 94 | use super::*; 95 | 96 | const YEA: Option<&str> = Some("1"); 97 | const NAY: Option<&str> = Some("0"); 98 | const NOT_SET: Option<&str> = None; 99 | 100 | macro_rules! test_enabled { 101 | (failure: $failure:ident, general: $general:ident => $result:expr) => {{ 102 | assert_eq!(is_backtrace_enabled(|var| match var { 103 | FAILURE_BACKTRACE => $failure.map(OsString::from), 104 | GENERAL_BACKTRACE => $general.map(OsString::from), 105 | _ => panic!() 106 | }), $result); 107 | }} 108 | } 109 | 110 | #[test] 111 | fn always_enabled_if_failure_is_set_to_yes() { 112 | test_enabled!(failure: YEA, general: YEA => true); 113 | test_enabled!(failure: YEA, general: NOT_SET => true); 114 | test_enabled!(failure: YEA, general: NAY => true); 115 | } 116 | 117 | #[test] 118 | fn never_enabled_if_failure_is_set_to_no() { 119 | test_enabled!(failure: NAY, general: YEA => false); 120 | test_enabled!(failure: NAY, general: NOT_SET => false); 121 | test_enabled!(failure: NAY, general: NAY => false); 122 | } 123 | 124 | #[test] 125 | fn follows_general_if_failure_is_not_set() { 126 | test_enabled!(failure: NOT_SET, general: YEA => true); 127 | test_enabled!(failure: NOT_SET, general: NOT_SET => false); 128 | test_enabled!(failure: NOT_SET, general: NAY => false); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /failure-1.X/src/backtrace/mod.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Debug, Display}; 2 | 3 | macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) } 4 | macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) } 5 | 6 | without_backtrace! { 7 | /// A `Backtrace`. 8 | /// 9 | /// This is an opaque wrapper around the backtrace provided by 10 | /// libbacktrace. A variety of optimizations have been performed to avoid 11 | /// unnecessary or ill-advised work: 12 | /// 13 | /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` 14 | /// is an empty struct, and will be completely compiled away. 15 | /// - If this crate is run without the `RUST_BACKTRACE` environmental 16 | /// variable enabled, the backtrace will not be generated at runtime. 17 | /// - Even if a backtrace is generated, the most expensive part of 18 | /// generating a backtrace is symbol resolution. This backtrace does not 19 | /// perform symbol resolution until it is actually read (e.g. by 20 | /// printing it). If the Backtrace is never used for anything, symbols 21 | /// never get resolved. 22 | /// 23 | /// Even with these optimizations, including a backtrace in your failure 24 | /// may not be appropriate to your use case. You are not required to put a 25 | /// backtrace in a custom `Fail` type. 26 | /// 27 | /// > (We have detected that this crate was documented with no_std 28 | /// > compatibility turned on. The version of this crate that has been 29 | /// > documented here will never generate a backtrace.) 30 | pub struct Backtrace { 31 | _secret: (), 32 | } 33 | 34 | impl Backtrace { 35 | /// Constructs a new backtrace. This will only create a real backtrace 36 | /// if the crate is compiled in std mode and the `RUST_BACKTRACE` 37 | /// environmental variable is activated. 38 | /// 39 | /// > (We have detected that this crate was documented with no_std 40 | /// > compatibility turned on. The version of this crate that has been 41 | /// > documented here will never generate a backtrace.) 42 | pub fn new() -> Backtrace { 43 | Backtrace { _secret: () } 44 | } 45 | 46 | #[cfg(feature = "std")] 47 | pub(crate) fn none() -> Backtrace { 48 | Backtrace { _secret: () } 49 | } 50 | 51 | #[cfg(feature = "std")] 52 | pub(crate) fn is_none(&self) -> bool { 53 | true 54 | } 55 | } 56 | 57 | impl Default for Backtrace { 58 | fn default() -> Backtrace { 59 | Backtrace::new() 60 | } 61 | } 62 | 63 | impl Debug for Backtrace { 64 | fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { 65 | Ok(()) 66 | } 67 | } 68 | 69 | impl Display for Backtrace { 70 | fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { 71 | Ok(()) 72 | } 73 | } 74 | } 75 | 76 | with_backtrace! { 77 | extern crate backtrace; 78 | 79 | mod internal; 80 | 81 | use self::internal::InternalBacktrace; 82 | 83 | /// A `Backtrace`. 84 | /// 85 | /// This is an opaque wrapper around the backtrace provided by 86 | /// libbacktrace. A variety of optimizations have been performed to avoid 87 | /// unnecessary or ill-advised work: 88 | /// 89 | /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` 90 | /// is an empty struct, and will be completely compiled away. 91 | /// - If this crate is run without the `RUST_BACKTRACE` environmental 92 | /// variable enabled, the backtrace will not be generated at runtime. 93 | /// - Even if a backtrace is generated, the most expensive part of 94 | /// generating a backtrace is symbol resolution. This backtrace does not 95 | /// perform symbol resolution until it is actually read (e.g. by 96 | /// printing it). If the Backtrace is never used for anything, symbols 97 | /// never get resolved. 98 | /// 99 | /// Even with these optimizations, including a backtrace in your failure 100 | /// may not be appropriate to your use case. You are not required to put a 101 | /// backtrace in a custom `Fail` type. 102 | pub struct Backtrace { 103 | internal: InternalBacktrace 104 | } 105 | 106 | impl Backtrace { 107 | /// Constructs a new backtrace. This will only create a real backtrace 108 | /// if the crate is compiled in std mode and the `RUST_BACKTRACE` 109 | /// environmental variable is activated. 110 | pub fn new() -> Backtrace { 111 | Backtrace { internal: InternalBacktrace::new() } 112 | } 113 | 114 | pub(crate) fn none() -> Backtrace { 115 | Backtrace { internal: InternalBacktrace::none() } 116 | } 117 | 118 | pub(crate) fn is_none(&self) -> bool { 119 | self.internal.is_none() 120 | } 121 | } 122 | 123 | impl Default for Backtrace { 124 | fn default() -> Backtrace { 125 | Backtrace::new() 126 | } 127 | } 128 | 129 | impl Debug for Backtrace { 130 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 131 | if let Some(bt) = self.internal.as_backtrace() { 132 | bt.fmt(f) 133 | } else { Ok(()) } 134 | } 135 | } 136 | 137 | impl Display for Backtrace { 138 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 139 | if let Some(bt) = self.internal.as_backtrace() { 140 | bt.fmt(f) 141 | } else { Ok(()) } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /failure-1.X/src/compat.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display}; 2 | 3 | /// A compatibility wrapper around an error type from this crate. 4 | /// 5 | /// `Compat` implements `std::error::Error`, allowing the types from this 6 | /// crate to be passed to interfaces that expect a type of that trait. 7 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] 8 | pub struct Compat { 9 | pub(crate) error: E, 10 | } 11 | 12 | impl Display for Compat { 13 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14 | Display::fmt(&self.error, f) 15 | } 16 | } 17 | 18 | impl Compat { 19 | /// Unwraps this into the inner error. 20 | pub fn into_inner(self) -> E { 21 | self.error 22 | } 23 | } 24 | 25 | with_std! { 26 | use std::fmt::Debug; 27 | use std::error::Error as StdError; 28 | 29 | use Error; 30 | 31 | impl StdError for Compat { 32 | fn description(&self) -> &'static str { 33 | "An error has occurred." 34 | } 35 | } 36 | 37 | impl From for Box { 38 | fn from(error: Error) -> Box { 39 | Box::new(Compat { error }) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /failure-1.X/src/context.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | 3 | use Fail; 4 | 5 | without_std! { 6 | /// An error with context around it. 7 | /// 8 | /// The context is intended to be a human-readable, user-facing explanation for the 9 | /// error that has occurred. The underlying error is not assumed to be end-user-relevant 10 | /// information. 11 | /// 12 | /// The `Display` impl for `Context` only prints the human-readable context, while the 13 | /// `Debug` impl also prints the underlying error. 14 | pub struct Context { 15 | context: D, 16 | } 17 | 18 | impl Context { 19 | /// Creates a new context without an underlying error message. 20 | pub fn new(context: D) -> Context { 21 | Context { context } 22 | } 23 | 24 | /// Returns a reference to the context provided with this error. 25 | pub fn get_context(&self) -> &D { 26 | &self.context 27 | } 28 | 29 | pub(crate) fn with_err(context: D, _: E) -> Context { 30 | Context { context } 31 | } 32 | } 33 | 34 | impl Fail for Context { } 35 | 36 | impl Debug for Context { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 | write!(f, "{}", self.context) 39 | } 40 | } 41 | 42 | impl Display for Context { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | write!(f, "{}", self.context) 45 | } 46 | } 47 | } 48 | 49 | with_std! { 50 | use {Error, Backtrace}; 51 | 52 | /// An error with context around it. 53 | /// 54 | /// The context is intended to be a human-readable, user-facing explanation for the 55 | /// error that has occurred. The underlying error is not assumed to be end-user-relevant 56 | /// information. 57 | /// 58 | /// The `Display` impl for `Context` only prints the human-readable context, while the 59 | /// `Debug` impl also prints the underlying error. 60 | pub struct Context { 61 | context: D, 62 | failure: Either, 63 | } 64 | 65 | impl Context { 66 | /// Creates a new context without an underlying error message. 67 | pub fn new(context: D) -> Context { 68 | let failure = Either::This(Backtrace::new()); 69 | Context { context, failure } 70 | } 71 | 72 | /// Returns a reference to the context provided with this error. 73 | pub fn get_context(&self) -> &D { 74 | &self.context 75 | } 76 | 77 | pub(crate) fn with_err>(context: D, error: E) -> Context { 78 | let failure = Either::That(error.into()); 79 | Context { context, failure } 80 | } 81 | } 82 | 83 | impl Fail for Context { 84 | fn cause(&self) -> Option<&Fail> { 85 | self.failure.cause() 86 | } 87 | 88 | fn backtrace(&self) -> Option<&Backtrace> { 89 | Some(self.failure.backtrace()) 90 | } 91 | } 92 | 93 | impl Debug for Context { 94 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 95 | write!(f, "{:?}\n\n{}", self.failure, self.context) 96 | } 97 | } 98 | 99 | impl Display for Context { 100 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 101 | write!(f, "{}", self.context) 102 | } 103 | } 104 | 105 | enum Either { 106 | This(A), 107 | That(B), 108 | } 109 | 110 | impl Either { 111 | fn backtrace(&self) -> &Backtrace { 112 | match *self { 113 | Either::This(ref backtrace) => backtrace, 114 | Either::That(ref error) => error.backtrace(), 115 | } 116 | } 117 | 118 | fn cause(&self) -> Option<&Fail> { 119 | match *self { 120 | Either::This(_) => None, 121 | Either::That(ref error) => Some(error.cause()) 122 | } 123 | } 124 | } 125 | 126 | impl Debug for Either { 127 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 128 | match *self { 129 | Either::This(ref backtrace) => write!(f, "{:?}", backtrace), 130 | Either::That(ref error) => write!(f, "{:?}", error), 131 | } 132 | } 133 | } 134 | } 135 | 136 | impl From for Context where 137 | D: Display + Send + Sync + 'static 138 | { 139 | fn from(display: D) -> Context { 140 | Context::new(display) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /failure-1.X/src/error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | 3 | use core::mem; 4 | use core::ptr; 5 | 6 | use {Causes, Fail}; 7 | use backtrace::Backtrace; 8 | use context::Context; 9 | use compat::Compat; 10 | 11 | /// The `Error` type, which can contain any failure. 12 | /// 13 | /// Functions which accumulate many kinds of errors should return this type. 14 | /// All failures can be converted into it, so functions which catch those 15 | /// errors can be tried with `?` inside of a function that returns this kind 16 | /// of error. 17 | /// 18 | /// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` 19 | /// information, and can be downcast into the failure that underlies it for 20 | /// more detailed inspection. 21 | pub struct Error { 22 | pub(crate) inner: Box>, 23 | } 24 | 25 | pub(crate) struct Inner { 26 | backtrace: Backtrace, 27 | pub(crate) failure: F, 28 | } 29 | 30 | impl From for Error { 31 | fn from(failure: F) -> Error { 32 | let inner: Inner = { 33 | let backtrace = if failure.backtrace().is_none() { 34 | Backtrace::new() 35 | } else { Backtrace::none() }; 36 | Inner { failure, backtrace } 37 | }; 38 | Error { inner: Box::new(inner) } 39 | } 40 | } 41 | 42 | impl Error { 43 | /// Returns a reference to the underlying cause of this `Error`. Unlike the 44 | /// method on `Fail`, this does not return an `Option`. The `Error` type 45 | /// always has an underlying failure. 46 | pub fn cause(&self) -> &Fail { 47 | &self.inner.failure 48 | } 49 | 50 | /// Gets a reference to the `Backtrace` for this `Error`. 51 | /// 52 | /// If the failure this wrapped carried a backtrace, that backtrace will 53 | /// be returned. Otherwise, the backtrace will have been constructed at 54 | /// the point that failure was cast into the `Error` type. 55 | pub fn backtrace(&self) -> &Backtrace { 56 | self.inner.failure.backtrace().unwrap_or(&self.inner.backtrace) 57 | } 58 | 59 | /// Provides context for this `Error`. 60 | /// 61 | /// This can provide additional information about this error, appropriate 62 | /// to the semantics of the current layer. That is, if you have a 63 | /// lower-level error, such as an IO error, you can provide additional context 64 | /// about what that error means in the context of your function. This 65 | /// gives users of this function more information about what has gone 66 | /// wrong. 67 | /// 68 | /// This takes any type that implements `Display`, as well as 69 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 70 | /// or a string literal, or a failure, or some other custom context-carrying 71 | /// type. 72 | pub fn context(self, context: D) -> Context { 73 | Context::with_err(context, self) 74 | } 75 | 76 | /// Wraps `Error` in a compatibility type. 77 | /// 78 | /// This type implements the `Error` trait from `std::error`. If you need 79 | /// to pass failure's `Error` to an interface that takes any `Error`, you 80 | /// can use this method to get a compatible type. 81 | pub fn compat(self) -> Compat { 82 | Compat { error: self } 83 | } 84 | 85 | /// Attempts to downcast this `Error` to a particular `Fail` type. 86 | /// 87 | /// This downcasts by value, returning an owned `T` if the underlying 88 | /// failure is of the type `T`. For this reason it returns a `Result` - in 89 | /// the case that the underlying error is of a different type, the 90 | /// original `Error` is returned. 91 | pub fn downcast(self) -> Result { 92 | let ret: Option = self.downcast_ref().map(|fail| { 93 | unsafe { 94 | // drop the backtrace 95 | let _ = ptr::read(&self.inner.backtrace as *const Backtrace); 96 | // read out the fail type 97 | ptr::read(fail as *const T) 98 | } 99 | }); 100 | match ret { 101 | Some(ret) => { 102 | // forget self (backtrace is dropped, failure is moved 103 | mem::forget(self); 104 | Ok(ret) 105 | } 106 | _ => Err(self) 107 | } 108 | } 109 | 110 | /// Returns the "root cause" of this error - the last value in the 111 | /// cause chain which does not return an underlying `cause`. 112 | pub fn root_cause(&self) -> &Fail { 113 | ::find_root_cause(self.cause()) 114 | } 115 | 116 | /// Attempts to downcast this `Error` to a particular `Fail` type by 117 | /// reference. 118 | /// 119 | /// If the underlying error is not of type `T`, this will return `None`. 120 | pub fn downcast_ref(&self) -> Option<&T> { 121 | self.inner.failure.downcast_ref() 122 | } 123 | 124 | /// Attempts to downcast this `Error` to a particular `Fail` type by 125 | /// mutable reference. 126 | /// 127 | /// If the underlying error is not of type `T`, this will return `None`. 128 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 129 | self.inner.failure.downcast_mut() 130 | } 131 | 132 | /// Returns a iterator over the causes of the `Error`, beginning with 133 | /// the failure returned by the `cause` method and ending with the failure 134 | /// returned by `root_cause`. 135 | pub fn causes(&self) -> Causes { 136 | Causes { fail: Some(self.cause()) } 137 | } 138 | } 139 | 140 | impl Display for Error { 141 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 142 | Display::fmt(&self.inner.failure, f) 143 | } 144 | } 145 | 146 | impl Debug for Error { 147 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 148 | if self.inner.backtrace.is_none() { 149 | Debug::fmt(&self.inner.failure, f) 150 | } else { 151 | write!(f, "{:?}\n\n{:?}", &self.inner.failure, self.inner.backtrace) 152 | } 153 | } 154 | } 155 | 156 | #[cfg(test)] 157 | mod test { 158 | fn assert_just_data() { } 159 | 160 | #[test] 161 | fn assert_error_is_just_data() { 162 | assert_just_data::(); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /failure-1.X/src/error_message.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | 3 | use Fail; 4 | use Error; 5 | 6 | /// Constructs a `Fail` type from a string. 7 | /// 8 | /// This is a convenient way to turn a string into an error value that 9 | /// can be passed around, if you do not want to create a new `Fail` type for 10 | /// this use case. 11 | pub fn err_msg(msg: D) -> Error { 12 | Error::from(ErrorMessage { msg }) 13 | } 14 | 15 | /// A `Fail` type that just contains an error message. You can construct 16 | /// this from the `err_msg` function. 17 | #[derive(Debug)] 18 | struct ErrorMessage { 19 | msg: D, 20 | } 21 | 22 | impl Fail for ErrorMessage { } 23 | 24 | impl Display for ErrorMessage { 25 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 26 | Display::fmt(&self.msg, f) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /failure-1.X/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An experimental new error-handling library. Guide-style introduction 2 | //! is available [here](https://boats.gitlab.io/failure/). 3 | //! 4 | //! The primary items exported by this library are: 5 | //! 6 | //! - `Fail`: a new trait for custom error types in Rust. 7 | //! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them 8 | //! at higher levels. 9 | //! 10 | //! As a general rule, library authors should create their own error types and 11 | //! implement `Fail` for them, whereas application authors should primarily 12 | //! deal with the `Error` type. There are exceptions to this rule, though, in 13 | //! both directions, and users should do whatever seems most appropriate to 14 | //! their situation. 15 | #![cfg_attr(not(feature = "std"), no_std)] 16 | #![deny(missing_docs)] 17 | #![cfg_attr(feature = "small-error", feature(extern_types, allocator_api))] 18 | 19 | macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } 20 | macro_rules! without_std { ($($i:item)*) => ($(#[cfg(not(feature = "std"))]$i)*) } 21 | 22 | mod backtrace; 23 | mod compat; 24 | mod context; 25 | mod result_ext; 26 | 27 | use core::any::TypeId; 28 | use core::fmt::{Debug, Display}; 29 | 30 | pub use backtrace::Backtrace; 31 | pub use compat::Compat; 32 | pub use context::Context; 33 | pub use result_ext::ResultExt; 34 | 35 | #[cfg(feature = "failure_derive")] 36 | #[allow(unused_imports)] 37 | #[macro_use] 38 | extern crate failure_derive; 39 | 40 | #[cfg(feature = "failure_derive")] 41 | #[doc(hidden)] 42 | pub use failure_derive::*; 43 | 44 | #[cfg(feature = "display_derive")] 45 | #[allow(unused_imports)] 46 | #[macro_use] 47 | extern crate display_derive; 48 | 49 | #[cfg(feature = "display_derive")] 50 | #[doc(hidden)] 51 | pub use display_derive::*; 52 | 53 | with_std! { 54 | extern crate core; 55 | 56 | mod sync_failure; 57 | pub use sync_failure::SyncFailure; 58 | 59 | #[cfg_attr(feature = "small-error", path = "./small_error.rs")] 60 | mod error; 61 | 62 | use std::error::Error as StdError; 63 | 64 | pub use error::Error; 65 | 66 | mod macros; 67 | mod error_message; 68 | pub use error_message::err_msg; 69 | } 70 | 71 | 72 | /// The `Fail` trait. 73 | /// 74 | /// Implementors of this trait are called 'failures'. 75 | /// 76 | /// All error types should implement `Fail`, which provides a baseline of 77 | /// functionality that they all share. 78 | /// 79 | /// `Fail` has no required methods, but it does require that your type 80 | /// implement several other traits: 81 | /// 82 | /// - `Display`: to print a user-friendly representation of the error. 83 | /// - `Debug`: to print a verbose, developer-focused representation of the 84 | /// error. 85 | /// - `Send + Sync`: Your error type is required to be safe to transfer to and 86 | /// reference from another thread 87 | /// 88 | /// Additionally, all failures must be `'static`. This enables downcasting. 89 | /// 90 | /// `Fail` provides several methods with default implementations. Two of these 91 | /// may be appropriate to override depending on the definition of your 92 | /// particular failure: the `cause` and `backtrace` methods. 93 | /// 94 | /// The `failure_derive` crate provides a way to derive the `Fail` trait for 95 | /// your type. Additionally, all types that already implement 96 | /// `std::error::Error`, and are also `Send`, `Sync`, and `'static`, implement 97 | /// `Fail` by a blanket impl. 98 | pub trait Fail: Display + Debug + Send + Sync + 'static { 99 | /// Returns a reference to the underlying cause of this failure, if it 100 | /// is an error that wraps other errors. 101 | /// 102 | /// Returns `None` if this failure does not have another error as its 103 | /// underlying cause. By default, this returns `None`. 104 | /// 105 | /// This should **never** return a reference to `self`, but only return 106 | /// `Some` when it can return a **different** failure. Users may loop 107 | /// over the cause chain, and returning `self` would result in an infinite 108 | /// loop. 109 | fn cause(&self) -> Option<&Fail> { 110 | None 111 | } 112 | 113 | /// Returns a reference to the `Backtrace` carried by this failure, if it 114 | /// carries one. 115 | /// 116 | /// Returns `None` if this failure does not carry a backtrace. By 117 | /// default, this returns `None`. 118 | fn backtrace(&self) -> Option<&Backtrace> { 119 | None 120 | } 121 | 122 | /// Provides context for this failure. 123 | /// 124 | /// This can provide additional information about this error, appropriate 125 | /// to the semantics of the current layer. That is, if you have a 126 | /// lower-level error, such as an IO error, you can provide additional context 127 | /// about what that error means in the context of your function. This 128 | /// gives users of this function more information about what has gone 129 | /// wrong. 130 | /// 131 | /// This takes any type that implements `Display`, as well as 132 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 133 | /// or a string literal, or another failure, or some other custom context-carrying 134 | /// type. 135 | fn context(self, context: D) -> Context where 136 | D: Display + Send + Sync + 'static, 137 | Self: Sized, 138 | { 139 | Context::with_err(context, self) 140 | } 141 | 142 | /// Wraps this failure in a compatibility wrapper that implements 143 | /// `std::error::Error`. 144 | /// 145 | /// This allows failures to be compatible with older crates that 146 | /// expect types that implement the `Error` trait from `std::error`. 147 | fn compat(self) -> Compat where 148 | Self: Sized, 149 | { 150 | Compat { error: self } 151 | } 152 | 153 | /// Returns a iterator over the causes of this `Fail` with itself 154 | /// as the first item and the `root_cause` as the final item. 155 | fn causes(&self) -> Causes where Self: Sized { 156 | Causes { fail: Some(self) } 157 | } 158 | 159 | /// Returns the "root cause" of this `Fail` - the last value in the 160 | /// cause chain which does not return an underlying `cause`. 161 | /// 162 | /// If this type does not have a cause, `self` is returned, because 163 | /// it is its own root cause. 164 | fn root_cause(&self) -> &Fail where 165 | Self: Sized, 166 | { 167 | find_root_cause(self) 168 | } 169 | 170 | #[doc(hidden)] 171 | fn __private_get_type_id__(&self) -> TypeId { 172 | TypeId::of::() 173 | } 174 | } 175 | 176 | impl Fail { 177 | /// Attempts to downcast this failure to a concrete type by reference. 178 | /// 179 | /// If the underlying error is not of type `T`, this will return `None`. 180 | pub fn downcast_ref(&self) -> Option<&T> { 181 | if self.__private_get_type_id__() == TypeId::of::() { 182 | unsafe { Some(&*(self as *const Fail as *const T)) } 183 | } else { 184 | None 185 | } 186 | } 187 | 188 | /// Attempts to downcast this failure to a concrete type by mutable 189 | /// reference. 190 | /// 191 | /// If the underlying error is not of type `T`, this will return `None`. 192 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 193 | if self.__private_get_type_id__() == TypeId::of::() { 194 | unsafe { Some(&mut *(self as *mut Fail as *mut T)) } 195 | } else { 196 | None 197 | } 198 | } 199 | 200 | 201 | /// Returns the "root cause" of this `Fail` - the last value in the 202 | /// cause chain which does not return an underlying `cause`. 203 | /// 204 | /// If this type does not have a cause, `self` is returned, because 205 | /// it is its own root cause. 206 | pub fn root_cause(&self) -> &Fail { 207 | find_root_cause(self) 208 | } 209 | 210 | /// Returns a iterator over the causes of this `Fail` with itself 211 | /// as the first item and the `root_cause` as the final item. 212 | pub fn causes(&self) -> Causes { 213 | Causes { fail: Some(self) } 214 | } 215 | } 216 | 217 | #[cfg(feature = "std")] 218 | impl Fail for E {} 219 | 220 | #[cfg(feature = "std")] 221 | impl Fail for Box { 222 | fn cause(&self) -> Option<&Fail> { 223 | (**self).cause() 224 | } 225 | 226 | fn backtrace(&self) -> Option<&Backtrace> { 227 | (**self).backtrace() 228 | } 229 | } 230 | 231 | /// A iterator over the causes of a `Fail` 232 | pub struct Causes<'f> { 233 | fail: Option<&'f Fail>, 234 | } 235 | 236 | impl<'f> Iterator for Causes<'f> { 237 | type Item = &'f Fail; 238 | fn next(&mut self) -> Option<&'f Fail> { 239 | self.fail.map(|fail| { 240 | self.fail = fail.cause(); 241 | fail 242 | }) 243 | } 244 | } 245 | 246 | fn find_root_cause(mut fail: &Fail) -> &Fail { 247 | while let Some(cause) = fail.cause() { 248 | fail = cause; 249 | } 250 | 251 | fail 252 | } 253 | -------------------------------------------------------------------------------- /failure-1.X/src/macros.rs: -------------------------------------------------------------------------------- 1 | /// "Throw" an error, returning it early. 2 | /// 3 | /// Like the `?` operator, this performs a conversion into the return type of 4 | /// the function you are early returning from. 5 | /// 6 | /// ``` 7 | /// #[macro_use] extern crate failure; 8 | /// 9 | /// #[derive(Fail, Debug, Display)] 10 | /// #[display(fmt = "An error occurred.")] 11 | /// struct CustomFailure; 12 | /// 13 | /// fn example(success: bool) -> Result<(), failure::Error> { 14 | /// if !success { 15 | /// throw!(CustomFailure); 16 | /// } 17 | /// 18 | /// Ok(()) 19 | /// } 20 | /// 21 | /// # fn main() { 22 | /// # assert!(example(true).is_ok()); 23 | /// # assert!(example(false).is_err()); 24 | /// # } 25 | /// ``` 26 | #[macro_export] 27 | macro_rules! throw { 28 | ($e:expr) => { 29 | return Err(::std::convert::Into::into($e)); 30 | } 31 | } 32 | 33 | /// Early return with an error made from a string. 34 | /// 35 | /// Unlike `throw!`, which expects a type that implements `Fail`, `bail!` 36 | /// expects to receive standard string interpolation. 37 | /// 38 | /// ``` 39 | /// #[macro_use] extern crate failure; 40 | /// 41 | /// fn example(success: bool) -> Result<(), failure::Error> { 42 | /// if !success { 43 | /// bail!("Unsuccessful: {}", success); 44 | /// } 45 | /// 46 | /// Ok(()) 47 | /// } 48 | /// 49 | /// # fn main() { 50 | /// # assert!(example(true).is_ok()); 51 | /// # assert!(example(false).is_err()); 52 | /// # } 53 | /// ``` 54 | #[macro_export] 55 | macro_rules! bail { 56 | ($e:expr) => { 57 | return Err($crate::err_msg::<&'static str>($e)); 58 | }; 59 | ($fmt:expr, $($arg:tt)+) => { 60 | return Err($crate::err_msg::(format!($fmt, $($arg)+))); 61 | }; 62 | } 63 | 64 | /// Early return with a string-based error if a condition isn't met. 65 | /// 66 | /// If `bail!` is analogous to `panic!`, `ensure!` is analogous to `assert!`. 67 | /// 68 | /// Like the `bail!` macro, this must take a string, it cannot take an 69 | /// arbitrary error type. If you want to throw a custom error, you should 70 | /// use an `if` statement and the `throw!` macro. 71 | #[macro_export] 72 | macro_rules! ensure { 73 | ($cond:expr, $e:expr) => { 74 | if !($cond) { 75 | bail!($e); 76 | } 77 | }; 78 | ($cond:expr, $fmt:expr, $($arg:tt)+) => { 79 | if !($cond) { 80 | bail!($fmt, $($arg)+); 81 | } 82 | }; 83 | } 84 | 85 | /// Construct an error from a format string without returning it. 86 | /// 87 | /// Unlike `bail!`, this does not terminate the function, it just evaluates 88 | /// to an `Error`, which you can do other things with. 89 | #[macro_export] 90 | macro_rules! format_err { 91 | ($e:expr) => { $crate::err_msg::<&'static str>($e) }; 92 | ($fmt:expr, $($arg:tt)+) => { $crate::err_msg::(format!($fmt, $($arg)+)) }; 93 | } 94 | -------------------------------------------------------------------------------- /failure-1.X/src/result_ext.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Display; 2 | 3 | use {Fail, Compat, Context}; 4 | 5 | /// Extension methods for `Result`. 6 | pub trait ResultExt { 7 | /// Wraps the error in `Compat` to make it compatible with older error 8 | /// handling APIs that expect `std::error::Error`. 9 | fn compat(self) -> Result>; 10 | 11 | /// Wraps the error type in a context type. 12 | fn context(self, context: D) -> Result> where 13 | D: Display + Send + Sync + 'static; 14 | 15 | /// Wraps the error type in a context type generated by looking at the 16 | /// error value. 17 | fn with_context(self, f: F) -> Result> where 18 | F: FnOnce(&E) -> D, 19 | D: Display + Send + Sync + 'static; 20 | } 21 | 22 | impl ResultExt for Result where 23 | E: Fail, 24 | { 25 | fn compat(self) -> Result> { 26 | self.map_err(|err| err.compat()) 27 | } 28 | 29 | fn context(self, context: D) -> Result> where 30 | D: Display + Send + Sync + 'static 31 | { 32 | self.map_err(|failure| failure.context(context)) 33 | } 34 | 35 | fn with_context(self, f: F) -> Result> where 36 | F: FnOnce(&E) -> D, 37 | D: Display + Send + Sync + 'static 38 | { 39 | self.map_err(|failure| { 40 | let context = f(&failure); 41 | failure.context(context) 42 | }) 43 | } 44 | } 45 | 46 | with_std! { 47 | use Error; 48 | 49 | impl ResultExt for Result { 50 | fn compat(self) -> Result> { 51 | self.map_err(|err| err.compat()) 52 | } 53 | 54 | fn context(self, context: D) -> Result> where 55 | D: Display + Send + Sync + 'static 56 | { 57 | self.map_err(|failure| failure.context(context)) 58 | } 59 | 60 | fn with_context(self, f: F) -> Result> where 61 | F: FnOnce(&Error) -> D, 62 | D: Display + Send + Sync + 'static 63 | { 64 | self.map_err(|failure| { 65 | let context = f(&failure); 66 | failure.context(context) 67 | }) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /failure-1.X/src/small_error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | use std::heap::{Heap, Alloc, Layout}; 3 | 4 | use core::mem; 5 | use core::ptr; 6 | 7 | use {Causes, Fail}; 8 | use backtrace::Backtrace; 9 | use context::Context; 10 | use compat::Compat; 11 | 12 | /// The `Error` type, which can contain any failure. 13 | /// 14 | /// Functions which accumulate many kinds of errors should return this type. 15 | /// All failures can be converted into it, so functions which catch those 16 | /// errors can be tried with `?` inside of a function that returns this kind 17 | /// of error. 18 | /// 19 | /// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` 20 | /// information, and can be downcast into the failure that underlies it for 21 | /// more detailed inspection. 22 | pub struct Error { 23 | inner: &'static mut Inner, 24 | } 25 | 26 | // Dynamically sized inner value 27 | struct Inner { 28 | backtrace: Backtrace, 29 | vtable: *const VTable, 30 | failure: FailData, 31 | } 32 | 33 | unsafe impl Send for Inner { } 34 | unsafe impl Sync for Inner { } 35 | 36 | extern { 37 | type VTable; 38 | type FailData; 39 | } 40 | 41 | struct InnerRaw { 42 | header: InnerHeader, 43 | failure: F, 44 | } 45 | 46 | struct InnerHeader { 47 | backtrace: Backtrace, 48 | vtable: *const VTable, 49 | } 50 | 51 | struct TraitObject { 52 | #[allow(dead_code)] 53 | data: *const FailData, 54 | vtable: *const VTable, 55 | } 56 | 57 | impl From for Error { 58 | fn from(failure: F) -> Error { 59 | let backtrace = if failure.backtrace().is_none() { 60 | Backtrace::new() 61 | } else { 62 | Backtrace::none() 63 | }; 64 | 65 | unsafe { 66 | let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; 67 | 68 | let ptr: *mut InnerRaw = match Heap.alloc(Layout::new::>()) { 69 | Ok(p) => p as *mut InnerRaw, 70 | Err(e) => Heap.oom(e), 71 | }; 72 | 73 | // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` 74 | ptr::write(ptr, InnerRaw { 75 | header: InnerHeader { 76 | backtrace, 77 | vtable, 78 | }, 79 | failure, 80 | }); 81 | 82 | let inner: &'static mut Inner = mem::transmute(ptr); 83 | 84 | Error { inner } 85 | } 86 | } 87 | } 88 | 89 | impl Inner { 90 | fn failure(&self) -> &Fail { 91 | unsafe { 92 | mem::transmute::(TraitObject { 93 | data: &self.failure as *const FailData, 94 | vtable: self.vtable, 95 | }) 96 | } 97 | } 98 | 99 | fn failure_mut(&mut self) -> &mut Fail { 100 | unsafe { 101 | mem::transmute::(TraitObject { 102 | data: &mut self.failure as *const FailData, 103 | vtable: self.vtable, 104 | }) 105 | } 106 | } 107 | } 108 | 109 | impl Error { 110 | /// Returns a reference to the underlying cause of this `Error`. Unlike the 111 | /// method on `Fail`, this does not return an `Option`. The `Error` type 112 | /// always has an underlying failure. 113 | pub fn cause(&self) -> &Fail { 114 | self.inner.failure() 115 | } 116 | 117 | /// Gets a reference to the `Backtrace` for this `Error`. 118 | /// 119 | /// If the failure this wrapped carried a backtrace, that backtrace will 120 | /// be returned. Otherwise, the backtrace will have been constructed at 121 | /// the point that failure was cast into the `Error` type. 122 | pub fn backtrace(&self) -> &Backtrace { 123 | self.inner.failure().backtrace().unwrap_or(&self.inner.backtrace) 124 | } 125 | 126 | /// Provides context for this `Error`. 127 | /// 128 | /// This can provide additional information about this error, appropriate 129 | /// to the semantics of the current layer. That is, if you have a 130 | /// lower-level error, such as an IO error, you can provide additional context 131 | /// about what that error means in the context of your function. This 132 | /// gives users of this function more information about what has gone 133 | /// wrong. 134 | /// 135 | /// This takes any type that implements `Display`, as well as 136 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 137 | /// or a string literal, or a failure, or some other custom context-carrying 138 | /// type. 139 | pub fn context(self, context: D) -> Context { 140 | Context::with_err(context, self) 141 | } 142 | 143 | /// Wraps `Error` in a compatibility type. 144 | /// 145 | /// This type implements the `Error` trait from `std::error`. If you need 146 | /// to pass failure's `Error` to an interface that takes any `Error`, you 147 | /// can use this method to get a compatible type. 148 | pub fn compat(self) -> Compat { 149 | Compat { error: self } 150 | } 151 | 152 | /// Attempts to downcast this `Error` to a particular `Fail` type. 153 | /// 154 | /// This downcasts by value, returning an owned `T` if the underlying 155 | /// failure is of the type `T`. For this reason it returns a `Result` - in 156 | /// the case that the underlying error is of a different type, the 157 | /// original `Error` is returned. 158 | pub fn downcast(self) -> Result { 159 | let ret: Option = self.downcast_ref().map(|fail| { 160 | unsafe { 161 | // drop the backtrace 162 | let _ = ptr::read(&self.inner.backtrace as *const Backtrace); 163 | // read out the fail type 164 | ptr::read(fail as *const T) 165 | } 166 | }); 167 | match ret { 168 | Some(ret) => { 169 | // forget self (backtrace is dropped, failure is moved 170 | mem::forget(self); 171 | Ok(ret) 172 | } 173 | _ => Err(self) 174 | } 175 | } 176 | 177 | /// Returns the "root cause" of this error - the last value in the 178 | /// cause chain which does not return an underlying `cause`. 179 | pub fn root_cause(&self) -> &Fail { 180 | ::find_root_cause(self.cause()) 181 | } 182 | 183 | /// Attempts to downcast this `Error` to a particular `Fail` type by 184 | /// reference. 185 | /// 186 | /// If the underlying error is not of type `T`, this will return `None`. 187 | pub fn downcast_ref(&self) -> Option<&T> { 188 | self.inner.failure().downcast_ref() 189 | } 190 | 191 | /// Attempts to downcast this `Error` to a particular `Fail` type by 192 | /// mutable reference. 193 | /// 194 | /// If the underlying error is not of type `T`, this will return `None`. 195 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 196 | self.inner.failure_mut().downcast_mut() 197 | } 198 | 199 | /// Returns a iterator over the causes of the `Error`, beginning with 200 | /// the failure returned by the `cause` method and ending with the failure 201 | /// returned by `root_cause`. 202 | pub fn causes(&self) -> Causes { 203 | Causes { fail: Some(self.cause()) } 204 | } 205 | } 206 | 207 | impl Display for Error { 208 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 209 | Display::fmt(self.inner.failure(), f) 210 | } 211 | } 212 | 213 | impl Debug for Error { 214 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 215 | if self.inner.backtrace.is_none() { 216 | Debug::fmt(self.inner.failure(), f) 217 | } else { 218 | write!(f, "{:?}\n\n{:?}", self.inner.failure(), self.inner.backtrace) 219 | } 220 | } 221 | } 222 | 223 | impl Drop for Error { 224 | fn drop(&mut self) { 225 | unsafe { 226 | let layout = { 227 | let header = Layout::new::(); 228 | header.extend(Layout::for_value(self.inner.failure())).unwrap().0 229 | }; 230 | Heap.dealloc(self.inner as *const _ as *const u8 as *mut u8, layout); 231 | } 232 | } 233 | } 234 | 235 | #[cfg(test)] 236 | mod test { 237 | use std::mem::size_of; 238 | use std::io; 239 | 240 | use super::Error; 241 | 242 | #[test] 243 | fn assert_error_is_just_data() { 244 | fn assert_just_data() { } 245 | assert_just_data::(); 246 | } 247 | 248 | #[test] 249 | fn assert_is_one_word() { 250 | assert_eq!(size_of::(), size_of::()); 251 | } 252 | 253 | #[test] 254 | fn methods_seem_to_work() { 255 | let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); 256 | let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); 257 | assert!(error.downcast_ref::().is_some()); 258 | let _: ::Backtrace = *error.backtrace(); 259 | assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); 260 | assert_eq!(format!("{}", io_error), format!("{}", error)); 261 | drop(error); 262 | assert!(true); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /failure-1.X/src/sync_failure.rs: -------------------------------------------------------------------------------- 1 | use Fail; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display}; 4 | use std::sync::Mutex; 5 | 6 | /// Wrapper for `std` errors to make them `Sync`. 7 | /// 8 | /// This exists to coerce existing types that are only `Error + Send + 9 | /// 'static` into a `Fail`-compatible representation, most notably for 10 | /// types generated by `error-chain`. 11 | /// 12 | /// Unfortunately, this requires wrapping the error in a `Mutex`, which must 13 | /// be locked for every `Debug`/`Display`. Therefore, this should be 14 | /// something of a last resort in making the error work with `failure`. 15 | /// 16 | pub struct SyncFailure { 17 | inner: Mutex, 18 | } 19 | 20 | impl SyncFailure { 21 | /// Wraps a non-`Sync` `Error` in order to make it implement `Fail`. 22 | /// 23 | /// # Example 24 | /// 25 | /// ```rust 26 | /// extern crate failure; 27 | /// 28 | /// # use std::error::Error as StdError; 29 | /// # use std::fmt::{self, Display}; 30 | /// use failure::{Error, SyncFailure}; 31 | /// use std::cell::RefCell; 32 | /// 33 | /// #[derive(Debug)] 34 | /// struct NonSyncError { 35 | /// // RefCells are non-Sync, so structs containing them will be 36 | /// // non-Sync as well. 37 | /// count: RefCell, 38 | /// } 39 | /// 40 | /// // implement Display/Error for NonSyncError... 41 | /// # 42 | /// # impl StdError for NonSyncError { 43 | /// # fn description(&self) -> &str { 44 | /// # "oops!" 45 | /// # } 46 | /// # } 47 | /// # 48 | /// # impl Display for NonSyncError { 49 | /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | /// # write!(f, "oops!") 51 | /// # } 52 | /// # } 53 | /// 54 | /// fn returns_error() -> Result<(), NonSyncError> { 55 | /// // Do stuff 56 | /// # Ok(()) 57 | /// } 58 | /// 59 | /// fn my_function() -> Result<(), Error> { 60 | /// // without the map_err here, we end up with a compile error 61 | /// // complaining that NonSyncError doesn't implement Sync. 62 | /// returns_error().map_err(SyncFailure::new)?; 63 | /// // Do more stuff 64 | /// # Ok(()) 65 | /// } 66 | /// # 67 | /// # fn main() { 68 | /// # my_function().unwrap(); 69 | /// # } 70 | /// ``` 71 | /// 72 | pub fn new(err: E) -> Self { 73 | SyncFailure { 74 | inner: Mutex::new(err), 75 | } 76 | } 77 | } 78 | 79 | impl Display for SyncFailure 80 | where 81 | T: Display, 82 | { 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 84 | self.inner.lock().unwrap().fmt(f) 85 | } 86 | } 87 | 88 | impl Debug for SyncFailure 89 | where 90 | T: Debug, 91 | { 92 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 93 | (*self.inner.lock().unwrap()).fmt(f) 94 | } 95 | } 96 | 97 | impl Fail for SyncFailure {} 98 | -------------------------------------------------------------------------------- /failure_compat_shim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "failure_compat_shim" 3 | version = "1.0.0" 4 | authors = ["boats "] 5 | 6 | [dependencies.failure] 7 | version = "1.0.0" 8 | path = "../failure-1.X" 9 | default-features = false 10 | 11 | [features] 12 | default = ["std", "derive"] 13 | backtrace = ["failure/backtrace"] 14 | std = ["backtrace", "failure/std"] 15 | derive = ["failure/derive"] 16 | -------------------------------------------------------------------------------- /failure_compat_shim/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | 3 | pub use failure::*; 4 | -------------------------------------------------------------------------------- /travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | 5 | cargo_test() { 6 | cargo test "$@" || { exit 101; } 7 | } 8 | 9 | test_failure_in() { 10 | cd $1 11 | cargo_test 12 | cargo_test --no-default-features 13 | cargo_test --features backtrace 14 | test_derive_in "$1/failure_derive" 15 | cd $DIR 16 | } 17 | 18 | test_derive_in() { 19 | cd $1 20 | cargo_test 21 | cd $DIR 22 | } 23 | 24 | test_nightly_features_in() { 25 | cd $1 26 | cargo_test --features small-error 27 | cargo_test --all-features 28 | cd $DIR 29 | } 30 | 31 | main() { 32 | test_failure_in "$DIR/failure-1.X" 33 | test_failure_in "$DIR/failure-0.1.X" 34 | if [ "${TRAVIS_RUST_VERSION}" = "nightly" ]; then 35 | test_nightly_features_in "$DIR/failure-1.X" 36 | fi 37 | } 38 | 39 | main 40 | --------------------------------------------------------------------------------