├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── build.rs ├── rust-toolchain.toml ├── src ├── backtrace.rs ├── chain.rs ├── context.rs ├── ensure.rs ├── error.rs ├── fmt.rs ├── kind.rs ├── lib.rs ├── macros.rs ├── nightly.rs ├── ptr.rs └── wrapper.rs └── tests ├── common └── mod.rs ├── compiletest.rs ├── crate ├── .gitignore ├── Cargo.toml └── test.rs ├── drop └── mod.rs ├── test_autotrait.rs ├── test_backtrace.rs ├── test_boxed.rs ├── test_chain.rs ├── test_context.rs ├── test_convert.rs ├── test_downcast.rs ├── test_ensure.rs ├── test_ffi.rs ├── test_fmt.rs ├── test_macros.rs ├── test_repr.rs ├── test_source.rs └── ui ├── chained-comparison.rs ├── chained-comparison.stderr ├── empty-ensure.rs ├── empty-ensure.stderr ├── ensure-nonbool.rs ├── ensure-nonbool.stderr ├── must-use.rs ├── must-use.stderr ├── no-impl.rs ├── no-impl.stderr ├── temporary-value.rs ├── temporary-value.stderr ├── wrong-interpolation.rs └── wrong-interpolation.stderr /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: dtolnay 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: [cron: "40 1 * * *"] 8 | 9 | permissions: 10 | contents: read 11 | 12 | env: 13 | RUSTFLAGS: -Dwarnings 14 | 15 | jobs: 16 | pre_ci: 17 | uses: dtolnay/.github/.github/workflows/pre_ci.yml@master 18 | 19 | test: 20 | name: Rust ${{matrix.rust}} 21 | needs: pre_ci 22 | if: needs.pre_ci.outputs.continue 23 | runs-on: ubuntu-latest 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | rust: [nightly, beta, stable, 1.82.0, 1.80.0, 1.70.0] 28 | timeout-minutes: 45 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: dtolnay/rust-toolchain@master 32 | with: 33 | toolchain: ${{matrix.rust}} 34 | components: rust-src 35 | - name: Enable type layout randomization 36 | run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV 37 | if: matrix.rust == 'nightly' 38 | - name: Enable nightly-only tests 39 | run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=anyhow_nightly_testing >> $GITHUB_ENV 40 | if: matrix.rust == 'nightly' 41 | - run: cargo test 42 | - run: cargo check --no-default-features 43 | - run: cargo check --features backtrace 44 | if: matrix.rust != '1.80.0' && matrix.rust != '1.70.0' 45 | - uses: actions/upload-artifact@v4 46 | if: matrix.rust == 'nightly' && always() 47 | with: 48 | name: Cargo.lock 49 | path: Cargo.lock 50 | continue-on-error: true 51 | 52 | build: 53 | name: Rust ${{matrix.rust}} 54 | needs: pre_ci 55 | if: needs.pre_ci.outputs.continue 56 | runs-on: ubuntu-latest 57 | strategy: 58 | fail-fast: false 59 | matrix: 60 | rust: [1.67.0, 1.65.0, 1.52.0, 1.51.0, 1.50.0, 1.39.0] 61 | timeout-minutes: 45 62 | steps: 63 | - uses: actions/checkout@v4 64 | - uses: dtolnay/rust-toolchain@master 65 | with: 66 | toolchain: ${{matrix.rust}} 67 | components: rust-src 68 | - run: cargo check --manifest-path tests/crate/Cargo.toml 69 | - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features 70 | 71 | minimal: 72 | name: Minimal versions 73 | needs: pre_ci 74 | if: needs.pre_ci.outputs.continue 75 | runs-on: ubuntu-latest 76 | timeout-minutes: 45 77 | steps: 78 | - uses: actions/checkout@v4 79 | - uses: dtolnay/rust-toolchain@nightly 80 | - run: cargo generate-lockfile -Z minimal-versions 81 | - run: cargo check --locked --features backtrace 82 | 83 | windows: 84 | name: Windows 85 | needs: pre_ci 86 | if: needs.pre_ci.outputs.continue 87 | runs-on: windows-latest 88 | timeout-minutes: 45 89 | steps: 90 | - uses: actions/checkout@v4 91 | - uses: dtolnay/rust-toolchain@stable 92 | with: 93 | components: rust-src 94 | - run: cargo check --features backtrace 95 | 96 | doc: 97 | name: Documentation 98 | needs: pre_ci 99 | if: needs.pre_ci.outputs.continue 100 | runs-on: ubuntu-latest 101 | timeout-minutes: 45 102 | env: 103 | RUSTDOCFLAGS: -Dwarnings 104 | steps: 105 | - uses: actions/checkout@v4 106 | - uses: dtolnay/rust-toolchain@nightly 107 | with: 108 | components: rust-src 109 | - uses: dtolnay/install@cargo-docs-rs 110 | - run: cargo docs-rs 111 | 112 | clippy: 113 | name: Clippy 114 | runs-on: ubuntu-latest 115 | if: github.event_name != 'pull_request' 116 | timeout-minutes: 45 117 | steps: 118 | - uses: actions/checkout@v4 119 | - uses: dtolnay/rust-toolchain@nightly 120 | with: 121 | components: clippy, rust-src 122 | - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic 123 | 124 | miri: 125 | name: Miri 126 | needs: pre_ci 127 | if: needs.pre_ci.outputs.continue 128 | runs-on: ubuntu-latest 129 | timeout-minutes: 45 130 | steps: 131 | - uses: actions/checkout@v4 132 | - uses: dtolnay/rust-toolchain@miri 133 | with: 134 | toolchain: nightly-2025-05-16 # https://github.com/rust-lang/miri/issues/4323 135 | - run: cargo miri setup 136 | - run: cargo miri test 137 | env: 138 | MIRIFLAGS: -Zmiri-strict-provenance 139 | 140 | outdated: 141 | name: Outdated 142 | runs-on: ubuntu-latest 143 | if: github.event_name != 'pull_request' 144 | timeout-minutes: 45 145 | steps: 146 | - uses: actions/checkout@v4 147 | - uses: dtolnay/rust-toolchain@stable 148 | - uses: dtolnay/install@cargo-outdated 149 | - run: cargo outdated --workspace --exit-code 1 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "anyhow" 3 | version = "1.0.98" 4 | authors = ["David Tolnay "] 5 | categories = ["rust-patterns", "no-std"] 6 | description = "Flexible concrete Error type built on std::error::Error" 7 | documentation = "https://docs.rs/anyhow" 8 | edition = "2018" 9 | keywords = ["error", "error-handling"] 10 | license = "MIT OR Apache-2.0" 11 | repository = "https://github.com/dtolnay/anyhow" 12 | rust-version = "1.39" 13 | 14 | [features] 15 | default = ["std"] 16 | std = [] 17 | 18 | [dependencies] 19 | # On compilers older than 1.65, features=["backtrace"] may be used to enable 20 | # backtraces via the `backtrace` crate. This feature has no effect on 1.65+ 21 | # besides bringing in an unused dependency, as `std::backtrace` is always 22 | # preferred. 23 | backtrace = { version = "0.3.51", optional = true } 24 | 25 | [dev-dependencies] 26 | futures = { version = "0.3", default-features = false } 27 | rustversion = "1.0.6" 28 | syn = { version = "2.0", features = ["full"] } 29 | thiserror = "2" 30 | trybuild = { version = "1.0.66", features = ["diff"] } 31 | 32 | [package.metadata.docs.rs] 33 | targets = ["x86_64-unknown-linux-gnu"] 34 | rustdoc-args = [ 35 | "--generate-link-to-definition", 36 | "--extern-html-root-url=core=https://doc.rust-lang.org", 37 | "--extern-html-root-url=alloc=https://doc.rust-lang.org", 38 | "--extern-html-root-url=std=https://doc.rust-lang.org", 39 | ] 40 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | Anyhow ¯\\\_(°ペ)\_/¯ 2 | ========================== 3 | 4 | [github](https://github.com/dtolnay/anyhow) 5 | [crates.io](https://crates.io/crates/anyhow) 6 | [docs.rs](https://docs.rs/anyhow) 7 | [build status](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster) 8 | 9 | This library provides [`anyhow::Error`][Error], a trait object based error type 10 | for easy idiomatic error handling in Rust applications. 11 | 12 | [Error]: https://docs.rs/anyhow/1.0/anyhow/struct.Error.html 13 | 14 | ```toml 15 | [dependencies] 16 | anyhow = "1.0" 17 | ``` 18 | 19 | *Compiler support: requires rustc 1.39+* 20 | 21 |
22 | 23 | ## Details 24 | 25 | - Use `Result`, or equivalently `anyhow::Result`, as the 26 | return type of any fallible function. 27 | 28 | Within the function, use `?` to easily propagate any error that implements the 29 | [`std::error::Error`] trait. 30 | 31 | ```rust 32 | use anyhow::Result; 33 | 34 | fn get_cluster_info() -> Result { 35 | let config = std::fs::read_to_string("cluster.json")?; 36 | let map: ClusterMap = serde_json::from_str(&config)?; 37 | Ok(map) 38 | } 39 | ``` 40 | 41 | [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html 42 | 43 | - Attach context to help the person troubleshooting the error understand where 44 | things went wrong. A low-level error like "No such file or directory" can be 45 | annoying to debug without more context about what higher level step the 46 | application was in the middle of. 47 | 48 | ```rust 49 | use anyhow::{Context, Result}; 50 | 51 | fn main() -> Result<()> { 52 | ... 53 | it.detach().context("Failed to detach the important thing")?; 54 | 55 | let content = std::fs::read(path) 56 | .with_context(|| format!("Failed to read instrs from {}", path))?; 57 | ... 58 | } 59 | ``` 60 | 61 | ```console 62 | Error: Failed to read instrs from ./path/to/instrs.json 63 | 64 | Caused by: 65 | No such file or directory (os error 2) 66 | ``` 67 | 68 | - Downcasting is supported and can be by value, by shared reference, or by 69 | mutable reference as needed. 70 | 71 | ```rust 72 | // If the error was caused by redaction, then return a 73 | // tombstone instead of the content. 74 | match root_cause.downcast_ref::() { 75 | Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), 76 | None => Err(error), 77 | } 78 | ``` 79 | 80 | - If using Rust ≥ 1.65, a backtrace is captured and printed with the error if 81 | the underlying error type does not already provide its own. In order to see 82 | backtraces, they must be enabled through the environment variables described 83 | in [`std::backtrace`]: 84 | 85 | - If you want panics and errors to both have backtraces, set 86 | `RUST_BACKTRACE=1`; 87 | - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; 88 | - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and 89 | `RUST_LIB_BACKTRACE=0`. 90 | 91 | [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables 92 | 93 | - Anyhow works with any error type that has an impl of `std::error::Error`, 94 | including ones defined in your crate. We do not bundle a `derive(Error)` macro 95 | but you can write the impls yourself or use a standalone macro like 96 | [thiserror]. 97 | 98 | ```rust 99 | use thiserror::Error; 100 | 101 | #[derive(Error, Debug)] 102 | pub enum FormatError { 103 | #[error("Invalid header (expected {expected:?}, got {found:?})")] 104 | InvalidHeader { 105 | expected: String, 106 | found: String, 107 | }, 108 | #[error("Missing attribute: {0}")] 109 | MissingAttribute(String), 110 | } 111 | ``` 112 | 113 | - One-off error messages can be constructed using the `anyhow!` macro, which 114 | supports string interpolation and produces an `anyhow::Error`. 115 | 116 | ```rust 117 | return Err(anyhow!("Missing attribute: {}", missing)); 118 | ``` 119 | 120 | A `bail!` macro is provided as a shorthand for the same early return. 121 | 122 | ```rust 123 | bail!("Missing attribute: {}", missing); 124 | ``` 125 | 126 |
127 | 128 | ## No-std support 129 | 130 | In no_std mode, almost all of the same API is available and works the same way. 131 | To depend on Anyhow in no_std mode, disable our default enabled "std" feature in 132 | Cargo.toml. A global allocator is required. 133 | 134 | ```toml 135 | [dependencies] 136 | anyhow = { version = "1.0", default-features = false } 137 | ``` 138 | 139 | With versions of Rust older than 1.81, no_std mode may require an additional 140 | `.map_err(Error::msg)` when working with a non-Anyhow error type inside a 141 | function that returns Anyhow's error type, as the trait that `?`-based error 142 | conversions are defined by is only available in std in those old versions. 143 | 144 |
145 | 146 | ## Comparison to failure 147 | 148 | The `anyhow::Error` type works something like `failure::Error`, but unlike 149 | failure ours is built around the standard library's `std::error::Error` trait 150 | rather than a separate trait `failure::Fail`. The standard library has adopted 151 | the necessary improvements for this to be possible as part of [RFC 2504]. 152 | 153 | [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md 154 | 155 |
156 | 157 | ## Comparison to thiserror 158 | 159 | Use Anyhow if you don't care what error type your functions return, you just 160 | want it to be easy. This is common in application code. Use [thiserror] if you 161 | are a library that wants to design your own dedicated error type(s) so that on 162 | failures the caller gets exactly the information that you choose. 163 | 164 | [thiserror]: https://github.com/dtolnay/thiserror 165 | 166 |
167 | 168 | #### License 169 | 170 | 171 | Licensed under either of Apache License, Version 172 | 2.0 or MIT license at your option. 173 | 174 | 175 |
176 | 177 | 178 | Unless you explicitly state otherwise, any contribution intentionally submitted 179 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 180 | be dual licensed as above, without any additional terms or conditions. 181 | 182 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::ffi::OsString; 3 | use std::fs; 4 | use std::io::ErrorKind; 5 | use std::iter; 6 | use std::path::Path; 7 | use std::process::{self, Command, Stdio}; 8 | use std::str; 9 | 10 | #[cfg(all(feature = "backtrace", not(feature = "std")))] 11 | compile_error! { 12 | "`backtrace` feature without `std` feature is not supported" 13 | } 14 | 15 | fn main() { 16 | let mut error_generic_member_access = false; 17 | if cfg!(feature = "std") { 18 | println!("cargo:rerun-if-changed=src/nightly.rs"); 19 | 20 | let consider_rustc_bootstrap; 21 | if compile_probe(false) { 22 | // This is a nightly or dev compiler, so it supports unstable 23 | // features regardless of RUSTC_BOOTSTRAP. No need to rerun build 24 | // script if RUSTC_BOOTSTRAP is changed. 25 | error_generic_member_access = true; 26 | consider_rustc_bootstrap = false; 27 | } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") { 28 | if compile_probe(true) { 29 | // This is a stable or beta compiler for which the user has set 30 | // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build 31 | // script if they change it. 32 | error_generic_member_access = true; 33 | consider_rustc_bootstrap = true; 34 | } else if rustc_bootstrap == "1" { 35 | // This compiler does not support the generic member access API 36 | // in the form that anyhow expects. No need to pay attention to 37 | // RUSTC_BOOTSTRAP. 38 | error_generic_member_access = false; 39 | consider_rustc_bootstrap = false; 40 | } else { 41 | // This is a stable or beta compiler for which RUSTC_BOOTSTRAP 42 | // is set to restrict the use of unstable features by this 43 | // crate. 44 | error_generic_member_access = false; 45 | consider_rustc_bootstrap = true; 46 | } 47 | } else { 48 | // Without RUSTC_BOOTSTRAP, this compiler does not support the 49 | // generic member access API in the form that anyhow expects, but 50 | // try again if the user turns on unstable features. 51 | error_generic_member_access = false; 52 | consider_rustc_bootstrap = true; 53 | } 54 | 55 | if error_generic_member_access { 56 | println!("cargo:rustc-cfg=std_backtrace"); 57 | println!("cargo:rustc-cfg=error_generic_member_access"); 58 | } 59 | 60 | if consider_rustc_bootstrap { 61 | println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); 62 | } 63 | } 64 | 65 | let rustc = match rustc_minor_version() { 66 | Some(rustc) => rustc, 67 | None => return, 68 | }; 69 | 70 | if rustc >= 80 { 71 | println!("cargo:rustc-check-cfg=cfg(anyhow_build_probe)"); 72 | println!("cargo:rustc-check-cfg=cfg(anyhow_nightly_testing)"); 73 | println!("cargo:rustc-check-cfg=cfg(anyhow_no_core_error)"); 74 | println!("cargo:rustc-check-cfg=cfg(anyhow_no_core_unwind_safe)"); 75 | println!("cargo:rustc-check-cfg=cfg(anyhow_no_fmt_arguments_as_str)"); 76 | println!("cargo:rustc-check-cfg=cfg(anyhow_no_ptr_addr_of)"); 77 | println!("cargo:rustc-check-cfg=cfg(anyhow_no_unsafe_op_in_unsafe_fn_lint)"); 78 | println!("cargo:rustc-check-cfg=cfg(error_generic_member_access)"); 79 | println!("cargo:rustc-check-cfg=cfg(std_backtrace)"); 80 | } 81 | 82 | if rustc < 51 { 83 | // core::ptr::addr_of 84 | // https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis 85 | println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of"); 86 | } 87 | 88 | if rustc < 52 { 89 | // core::fmt::Arguments::as_str 90 | // https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html#stabilized-apis 91 | println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str"); 92 | 93 | // #![deny(unsafe_op_in_unsafe_fn)] 94 | // https://github.com/rust-lang/rust/issues/71668 95 | println!("cargo:rustc-cfg=anyhow_no_unsafe_op_in_unsafe_fn_lint"); 96 | } 97 | 98 | if rustc < 56 { 99 | // core::panic::{UnwindSafe, RefUnwindSafe} 100 | // https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html#stabilized-apis 101 | println!("cargo:rustc-cfg=anyhow_no_core_unwind_safe"); 102 | } 103 | 104 | if !error_generic_member_access && cfg!(feature = "std") && rustc >= 65 { 105 | // std::backtrace::Backtrace 106 | // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis 107 | println!("cargo:rustc-cfg=std_backtrace"); 108 | } 109 | 110 | if rustc < 81 { 111 | // core::error::Error 112 | // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror 113 | println!("cargo:rustc-cfg=anyhow_no_core_error"); 114 | } 115 | } 116 | 117 | fn compile_probe(rustc_bootstrap: bool) -> bool { 118 | if env::var_os("RUSTC_STAGE").is_some() { 119 | // We are running inside rustc bootstrap. This is a highly non-standard 120 | // environment with issues such as: 121 | // 122 | // https://github.com/rust-lang/cargo/issues/11138 123 | // https://github.com/rust-lang/rust/issues/114839 124 | // 125 | // Let's just not use nightly features here. 126 | return false; 127 | } 128 | 129 | let rustc = cargo_env_var("RUSTC"); 130 | let out_dir = cargo_env_var("OUT_DIR"); 131 | let out_subdir = Path::new(&out_dir).join("probe"); 132 | let probefile = Path::new("src").join("nightly.rs"); 133 | 134 | if let Err(err) = fs::create_dir(&out_subdir) { 135 | if err.kind() != ErrorKind::AlreadyExists { 136 | eprintln!("Failed to create {}: {}", out_subdir.display(), err); 137 | process::exit(1); 138 | } 139 | } 140 | 141 | let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty()); 142 | let rustc_workspace_wrapper = 143 | env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty()); 144 | let mut rustc = rustc_wrapper 145 | .into_iter() 146 | .chain(rustc_workspace_wrapper) 147 | .chain(iter::once(rustc)); 148 | let mut cmd = Command::new(rustc.next().unwrap()); 149 | cmd.args(rustc); 150 | 151 | if !rustc_bootstrap { 152 | cmd.env_remove("RUSTC_BOOTSTRAP"); 153 | } 154 | 155 | cmd.stderr(Stdio::null()) 156 | .arg("--cfg=anyhow_build_probe") 157 | .arg("--edition=2018") 158 | .arg("--crate-name=anyhow") 159 | .arg("--crate-type=lib") 160 | .arg("--emit=dep-info,metadata") 161 | .arg("--cap-lints=allow") 162 | .arg("--out-dir") 163 | .arg(&out_subdir) 164 | .arg(probefile); 165 | 166 | if let Some(target) = env::var_os("TARGET") { 167 | cmd.arg("--target").arg(target); 168 | } 169 | 170 | // If Cargo wants to set RUSTFLAGS, use that. 171 | if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { 172 | if !rustflags.is_empty() { 173 | for arg in rustflags.split('\x1f') { 174 | cmd.arg(arg); 175 | } 176 | } 177 | } 178 | 179 | let success = match cmd.status() { 180 | Ok(status) => status.success(), 181 | Err(_) => false, 182 | }; 183 | 184 | // Clean up to avoid leaving nondeterministic absolute paths in the dep-info 185 | // file in OUT_DIR, which causes nonreproducible builds in build systems 186 | // that treat the entire OUT_DIR as an artifact. 187 | if let Err(err) = fs::remove_dir_all(&out_subdir) { 188 | if err.kind() != ErrorKind::NotFound { 189 | eprintln!("Failed to clean up {}: {}", out_subdir.display(), err); 190 | process::exit(1); 191 | } 192 | } 193 | 194 | success 195 | } 196 | 197 | fn rustc_minor_version() -> Option { 198 | let rustc = cargo_env_var("RUSTC"); 199 | let output = Command::new(rustc).arg("--version").output().ok()?; 200 | let version = str::from_utf8(&output.stdout).ok()?; 201 | let mut pieces = version.split('.'); 202 | if pieces.next() != Some("rustc 1") { 203 | return None; 204 | } 205 | pieces.next()?.parse().ok() 206 | } 207 | 208 | fn cargo_env_var(key: &str) -> OsString { 209 | env::var_os(key).unwrap_or_else(|| { 210 | eprintln!( 211 | "Environment variable ${} is not set during execution of build script", 212 | key, 213 | ); 214 | process::exit(1); 215 | }) 216 | } 217 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | components = ["rust-src"] 3 | -------------------------------------------------------------------------------- /src/backtrace.rs: -------------------------------------------------------------------------------- 1 | #[cfg(std_backtrace)] 2 | pub(crate) use std::backtrace::{Backtrace, BacktraceStatus}; 3 | 4 | #[cfg(all(not(std_backtrace), feature = "backtrace"))] 5 | pub(crate) use self::capture::{Backtrace, BacktraceStatus}; 6 | 7 | #[cfg(not(any(std_backtrace, feature = "backtrace")))] 8 | pub(crate) enum Backtrace {} 9 | 10 | #[cfg(std_backtrace)] 11 | macro_rules! impl_backtrace { 12 | () => { 13 | std::backtrace::Backtrace 14 | }; 15 | } 16 | 17 | #[cfg(all(not(std_backtrace), feature = "backtrace"))] 18 | macro_rules! impl_backtrace { 19 | () => { 20 | impl core::fmt::Debug + core::fmt::Display 21 | }; 22 | } 23 | 24 | #[cfg(any(std_backtrace, feature = "backtrace"))] 25 | macro_rules! backtrace { 26 | () => { 27 | Some(crate::backtrace::Backtrace::capture()) 28 | }; 29 | } 30 | 31 | #[cfg(not(any(std_backtrace, feature = "backtrace")))] 32 | macro_rules! backtrace { 33 | () => { 34 | None 35 | }; 36 | } 37 | 38 | #[cfg(error_generic_member_access)] 39 | macro_rules! backtrace_if_absent { 40 | ($err:expr) => { 41 | match $crate::nightly::request_ref_backtrace($err as &dyn core::error::Error) { 42 | Some(_) => None, 43 | None => backtrace!(), 44 | } 45 | }; 46 | } 47 | 48 | #[cfg(all( 49 | any(feature = "std", not(anyhow_no_core_error)), 50 | not(error_generic_member_access), 51 | any(std_backtrace, feature = "backtrace") 52 | ))] 53 | macro_rules! backtrace_if_absent { 54 | ($err:expr) => { 55 | backtrace!() 56 | }; 57 | } 58 | 59 | #[cfg(all( 60 | any(feature = "std", not(anyhow_no_core_error)), 61 | not(std_backtrace), 62 | not(feature = "backtrace"), 63 | ))] 64 | macro_rules! backtrace_if_absent { 65 | ($err:expr) => { 66 | None 67 | }; 68 | } 69 | 70 | #[cfg(all(not(std_backtrace), feature = "backtrace"))] 71 | mod capture { 72 | use alloc::borrow::{Cow, ToOwned as _}; 73 | use alloc::vec::Vec; 74 | use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName}; 75 | use core::cell::UnsafeCell; 76 | use core::fmt::{self, Debug, Display}; 77 | use core::sync::atomic::{AtomicUsize, Ordering}; 78 | use std::env; 79 | use std::path::{self, Path, PathBuf}; 80 | use std::sync::Once; 81 | 82 | pub(crate) struct Backtrace { 83 | inner: Inner, 84 | } 85 | 86 | pub(crate) enum BacktraceStatus { 87 | Unsupported, 88 | Disabled, 89 | Captured, 90 | } 91 | 92 | enum Inner { 93 | Unsupported, 94 | Disabled, 95 | Captured(LazilyResolvedCapture), 96 | } 97 | 98 | struct Capture { 99 | actual_start: usize, 100 | resolved: bool, 101 | frames: Vec, 102 | } 103 | 104 | struct BacktraceFrame { 105 | frame: Frame, 106 | symbols: Vec, 107 | } 108 | 109 | struct BacktraceSymbol { 110 | name: Option>, 111 | filename: Option, 112 | lineno: Option, 113 | colno: Option, 114 | } 115 | 116 | enum BytesOrWide { 117 | Bytes(Vec), 118 | Wide(Vec), 119 | } 120 | 121 | impl Debug for Backtrace { 122 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 123 | let capture = match &self.inner { 124 | Inner::Unsupported => return fmt.write_str(""), 125 | Inner::Disabled => return fmt.write_str(""), 126 | Inner::Captured(c) => c.force(), 127 | }; 128 | 129 | let frames = &capture.frames[capture.actual_start..]; 130 | 131 | write!(fmt, "Backtrace ")?; 132 | 133 | let mut dbg = fmt.debug_list(); 134 | 135 | for frame in frames { 136 | if frame.frame.ip().is_null() { 137 | continue; 138 | } 139 | 140 | dbg.entries(&frame.symbols); 141 | } 142 | 143 | dbg.finish() 144 | } 145 | } 146 | 147 | impl Debug for BacktraceFrame { 148 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 149 | let mut dbg = fmt.debug_list(); 150 | dbg.entries(&self.symbols); 151 | dbg.finish() 152 | } 153 | } 154 | 155 | impl Debug for BacktraceSymbol { 156 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 157 | write!(fmt, "{{ ")?; 158 | 159 | if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) { 160 | write!(fmt, "fn: \"{:#}\"", fn_name)?; 161 | } else { 162 | write!(fmt, "fn: ")?; 163 | } 164 | 165 | if let Some(fname) = self.filename.as_ref() { 166 | write!(fmt, ", file: \"{:?}\"", fname)?; 167 | } 168 | 169 | if let Some(line) = self.lineno { 170 | write!(fmt, ", line: {:?}", line)?; 171 | } 172 | 173 | write!(fmt, " }}") 174 | } 175 | } 176 | 177 | impl Debug for BytesOrWide { 178 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 179 | output_filename( 180 | fmt, 181 | match self { 182 | BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), 183 | BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), 184 | }, 185 | PrintFmt::Short, 186 | env::current_dir().as_ref().ok(), 187 | ) 188 | } 189 | } 190 | 191 | impl Backtrace { 192 | fn enabled() -> bool { 193 | static ENABLED: AtomicUsize = AtomicUsize::new(0); 194 | match ENABLED.load(Ordering::Relaxed) { 195 | 0 => {} 196 | 1 => return false, 197 | _ => return true, 198 | } 199 | let enabled = match env::var_os("RUST_LIB_BACKTRACE") { 200 | Some(s) => s != "0", 201 | None => match env::var_os("RUST_BACKTRACE") { 202 | Some(s) => s != "0", 203 | None => false, 204 | }, 205 | }; 206 | ENABLED.store(enabled as usize + 1, Ordering::Relaxed); 207 | enabled 208 | } 209 | 210 | #[inline(never)] // want to make sure there's a frame here to remove 211 | pub(crate) fn capture() -> Backtrace { 212 | if Backtrace::enabled() { 213 | Backtrace::create(Backtrace::capture as usize) 214 | } else { 215 | let inner = Inner::Disabled; 216 | Backtrace { inner } 217 | } 218 | } 219 | 220 | // Capture a backtrace which starts just before the function addressed 221 | // by `ip` 222 | fn create(ip: usize) -> Backtrace { 223 | let mut frames = Vec::new(); 224 | let mut actual_start = None; 225 | backtrace::trace(|frame| { 226 | frames.push(BacktraceFrame { 227 | frame: frame.clone(), 228 | symbols: Vec::new(), 229 | }); 230 | if frame.symbol_address() as usize == ip && actual_start.is_none() { 231 | actual_start = Some(frames.len() + 1); 232 | } 233 | true 234 | }); 235 | 236 | // If no frames came out assume that this is an unsupported platform 237 | // since `backtrace` doesn't provide a way of learning this right 238 | // now, and this should be a good enough approximation. 239 | let inner = if frames.is_empty() { 240 | Inner::Unsupported 241 | } else { 242 | Inner::Captured(LazilyResolvedCapture::new(Capture { 243 | actual_start: actual_start.unwrap_or(0), 244 | frames, 245 | resolved: false, 246 | })) 247 | }; 248 | 249 | Backtrace { inner } 250 | } 251 | 252 | pub(crate) fn status(&self) -> BacktraceStatus { 253 | match self.inner { 254 | Inner::Unsupported => BacktraceStatus::Unsupported, 255 | Inner::Disabled => BacktraceStatus::Disabled, 256 | Inner::Captured(_) => BacktraceStatus::Captured, 257 | } 258 | } 259 | } 260 | 261 | impl Display for Backtrace { 262 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 263 | let capture = match &self.inner { 264 | Inner::Unsupported => return fmt.write_str("unsupported backtrace"), 265 | Inner::Disabled => return fmt.write_str("disabled backtrace"), 266 | Inner::Captured(c) => c.force(), 267 | }; 268 | 269 | let full = fmt.alternate(); 270 | let (frames, style) = if full { 271 | (&capture.frames[..], PrintFmt::Full) 272 | } else { 273 | (&capture.frames[capture.actual_start..], PrintFmt::Short) 274 | }; 275 | 276 | // When printing paths we try to strip the cwd if it exists, 277 | // otherwise we just print the path as-is. Note that we also only do 278 | // this for the short format, because if it's full we presumably 279 | // want to print everything. 280 | let cwd = env::current_dir(); 281 | let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| { 282 | output_filename(fmt, path, style, cwd.as_ref().ok()) 283 | }; 284 | 285 | let mut f = BacktraceFmt::new(fmt, style, &mut print_path); 286 | f.add_context()?; 287 | for frame in frames { 288 | let mut f = f.frame(); 289 | if frame.symbols.is_empty() { 290 | f.print_raw(frame.frame.ip(), None, None, None)?; 291 | } else { 292 | for symbol in frame.symbols.iter() { 293 | f.print_raw_with_column( 294 | frame.frame.ip(), 295 | symbol.name.as_ref().map(|b| SymbolName::new(b)), 296 | symbol.filename.as_ref().map(|b| match b { 297 | BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), 298 | BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), 299 | }), 300 | symbol.lineno, 301 | symbol.colno, 302 | )?; 303 | } 304 | } 305 | } 306 | f.finish()?; 307 | Ok(()) 308 | } 309 | } 310 | 311 | struct LazilyResolvedCapture { 312 | sync: Once, 313 | capture: UnsafeCell, 314 | } 315 | 316 | impl LazilyResolvedCapture { 317 | fn new(capture: Capture) -> Self { 318 | LazilyResolvedCapture { 319 | sync: Once::new(), 320 | capture: UnsafeCell::new(capture), 321 | } 322 | } 323 | 324 | fn force(&self) -> &Capture { 325 | self.sync.call_once(|| { 326 | // Safety: This exclusive reference can't overlap with any 327 | // others. `Once` guarantees callers will block until this 328 | // closure returns. `Once` also guarantees only a single caller 329 | // will enter this closure. 330 | unsafe { &mut *self.capture.get() }.resolve(); 331 | }); 332 | 333 | // Safety: This shared reference can't overlap with the exclusive 334 | // reference above. 335 | unsafe { &*self.capture.get() } 336 | } 337 | } 338 | 339 | // Safety: Access to the inner value is synchronized using a thread-safe 340 | // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too 341 | unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {} 342 | 343 | impl Capture { 344 | fn resolve(&mut self) { 345 | // If we're already resolved, nothing to do! 346 | if self.resolved { 347 | return; 348 | } 349 | self.resolved = true; 350 | 351 | for frame in self.frames.iter_mut() { 352 | let symbols = &mut frame.symbols; 353 | let frame = &frame.frame; 354 | backtrace::resolve_frame(frame, |symbol| { 355 | symbols.push(BacktraceSymbol { 356 | name: symbol.name().map(|m| m.as_bytes().to_vec()), 357 | filename: symbol.filename_raw().map(|b| match b { 358 | BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), 359 | BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), 360 | }), 361 | lineno: symbol.lineno(), 362 | colno: symbol.colno(), 363 | }); 364 | }); 365 | } 366 | } 367 | } 368 | 369 | // Prints the filename of the backtrace frame. 370 | fn output_filename( 371 | fmt: &mut fmt::Formatter, 372 | bows: BytesOrWideString, 373 | print_fmt: PrintFmt, 374 | cwd: Option<&PathBuf>, 375 | ) -> fmt::Result { 376 | let file: Cow = match bows { 377 | #[cfg(unix)] 378 | BytesOrWideString::Bytes(bytes) => { 379 | use std::os::unix::ffi::OsStrExt; 380 | Path::new(std::ffi::OsStr::from_bytes(bytes)).into() 381 | } 382 | #[cfg(not(unix))] 383 | BytesOrWideString::Bytes(bytes) => { 384 | Path::new(std::str::from_utf8(bytes).unwrap_or("")).into() 385 | } 386 | #[cfg(windows)] 387 | BytesOrWideString::Wide(wide) => { 388 | use std::os::windows::ffi::OsStringExt; 389 | Cow::Owned(std::ffi::OsString::from_wide(wide).into()) 390 | } 391 | #[cfg(not(windows))] 392 | BytesOrWideString::Wide(_wide) => Path::new("").into(), 393 | }; 394 | if print_fmt == PrintFmt::Short && file.is_absolute() { 395 | if let Some(cwd) = cwd { 396 | if let Ok(stripped) = file.strip_prefix(&cwd) { 397 | if let Some(s) = stripped.to_str() { 398 | return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s); 399 | } 400 | } 401 | } 402 | } 403 | Display::fmt(&file.display(), fmt) 404 | } 405 | } 406 | 407 | fn _assert_send_sync() { 408 | fn assert() {} 409 | assert::(); 410 | } 411 | -------------------------------------------------------------------------------- /src/chain.rs: -------------------------------------------------------------------------------- 1 | use self::ChainState::*; 2 | use crate::StdError; 3 | 4 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 5 | use alloc::vec::{self, Vec}; 6 | 7 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 8 | pub(crate) use crate::Chain; 9 | 10 | #[cfg(all(not(feature = "std"), anyhow_no_core_error))] 11 | pub(crate) struct Chain<'a> { 12 | state: ChainState<'a>, 13 | } 14 | 15 | #[derive(Clone)] 16 | pub(crate) enum ChainState<'a> { 17 | Linked { 18 | next: Option<&'a (dyn StdError + 'static)>, 19 | }, 20 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 21 | Buffered { 22 | rest: vec::IntoIter<&'a (dyn StdError + 'static)>, 23 | }, 24 | } 25 | 26 | impl<'a> Chain<'a> { 27 | #[cold] 28 | pub fn new(head: &'a (dyn StdError + 'static)) -> Self { 29 | Chain { 30 | state: ChainState::Linked { next: Some(head) }, 31 | } 32 | } 33 | } 34 | 35 | impl<'a> Iterator for Chain<'a> { 36 | type Item = &'a (dyn StdError + 'static); 37 | 38 | fn next(&mut self) -> Option { 39 | match &mut self.state { 40 | Linked { next } => { 41 | let error = (*next)?; 42 | *next = error.source(); 43 | Some(error) 44 | } 45 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 46 | Buffered { rest } => rest.next(), 47 | } 48 | } 49 | 50 | fn size_hint(&self) -> (usize, Option) { 51 | let len = self.len(); 52 | (len, Some(len)) 53 | } 54 | } 55 | 56 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 57 | impl DoubleEndedIterator for Chain<'_> { 58 | fn next_back(&mut self) -> Option { 59 | match &mut self.state { 60 | Linked { mut next } => { 61 | let mut rest = Vec::new(); 62 | while let Some(cause) = next { 63 | next = cause.source(); 64 | rest.push(cause); 65 | } 66 | let mut rest = rest.into_iter(); 67 | let last = rest.next_back(); 68 | self.state = Buffered { rest }; 69 | last 70 | } 71 | Buffered { rest } => rest.next_back(), 72 | } 73 | } 74 | } 75 | 76 | impl ExactSizeIterator for Chain<'_> { 77 | fn len(&self) -> usize { 78 | match &self.state { 79 | Linked { mut next } => { 80 | let mut len = 0; 81 | while let Some(cause) = next { 82 | next = cause.source(); 83 | len += 1; 84 | } 85 | len 86 | } 87 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 88 | Buffered { rest } => rest.len(), 89 | } 90 | } 91 | } 92 | 93 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 94 | impl Default for Chain<'_> { 95 | fn default() -> Self { 96 | Chain { 97 | state: ChainState::Buffered { 98 | rest: Vec::new().into_iter(), 99 | }, 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use crate::error::ContextError; 2 | use crate::{Context, Error, StdError}; 3 | use core::convert::Infallible; 4 | use core::fmt::{self, Debug, Display, Write}; 5 | 6 | #[cfg(error_generic_member_access)] 7 | use crate::nightly::{self, Request}; 8 | 9 | mod ext { 10 | use super::*; 11 | 12 | pub trait StdError { 13 | fn ext_context(self, context: C) -> Error 14 | where 15 | C: Display + Send + Sync + 'static; 16 | } 17 | 18 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 19 | impl StdError for E 20 | where 21 | E: crate::StdError + Send + Sync + 'static, 22 | { 23 | fn ext_context(self, context: C) -> Error 24 | where 25 | C: Display + Send + Sync + 'static, 26 | { 27 | let backtrace = backtrace_if_absent!(&self); 28 | Error::construct_from_context(context, self, backtrace) 29 | } 30 | } 31 | 32 | impl StdError for Error { 33 | fn ext_context(self, context: C) -> Error 34 | where 35 | C: Display + Send + Sync + 'static, 36 | { 37 | self.context(context) 38 | } 39 | } 40 | } 41 | 42 | impl Context for Result 43 | where 44 | E: ext::StdError + Send + Sync + 'static, 45 | { 46 | fn context(self, context: C) -> Result 47 | where 48 | C: Display + Send + Sync + 'static, 49 | { 50 | // Not using map_err to save 2 useless frames off the captured backtrace 51 | // in ext_context. 52 | match self { 53 | Ok(ok) => Ok(ok), 54 | Err(error) => Err(error.ext_context(context)), 55 | } 56 | } 57 | 58 | fn with_context(self, context: F) -> Result 59 | where 60 | C: Display + Send + Sync + 'static, 61 | F: FnOnce() -> C, 62 | { 63 | match self { 64 | Ok(ok) => Ok(ok), 65 | Err(error) => Err(error.ext_context(context())), 66 | } 67 | } 68 | } 69 | 70 | /// ``` 71 | /// # type T = (); 72 | /// # 73 | /// use anyhow::{Context, Result}; 74 | /// 75 | /// fn maybe_get() -> Option { 76 | /// # const IGNORE: &str = stringify! { 77 | /// ... 78 | /// # }; 79 | /// # unimplemented!() 80 | /// } 81 | /// 82 | /// fn demo() -> Result<()> { 83 | /// let t = maybe_get().context("there is no T")?; 84 | /// # const IGNORE: &str = stringify! { 85 | /// ... 86 | /// # }; 87 | /// # unimplemented!() 88 | /// } 89 | /// ``` 90 | impl Context for Option { 91 | fn context(self, context: C) -> Result 92 | where 93 | C: Display + Send + Sync + 'static, 94 | { 95 | // Not using ok_or_else to save 2 useless frames off the captured 96 | // backtrace. 97 | match self { 98 | Some(ok) => Ok(ok), 99 | None => Err(Error::construct_from_display(context, backtrace!())), 100 | } 101 | } 102 | 103 | fn with_context(self, context: F) -> Result 104 | where 105 | C: Display + Send + Sync + 'static, 106 | F: FnOnce() -> C, 107 | { 108 | match self { 109 | Some(ok) => Ok(ok), 110 | None => Err(Error::construct_from_display(context(), backtrace!())), 111 | } 112 | } 113 | } 114 | 115 | impl Debug for ContextError 116 | where 117 | C: Display, 118 | E: Debug, 119 | { 120 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 121 | f.debug_struct("Error") 122 | .field("context", &Quoted(&self.context)) 123 | .field("source", &self.error) 124 | .finish() 125 | } 126 | } 127 | 128 | impl Display for ContextError 129 | where 130 | C: Display, 131 | { 132 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 133 | Display::fmt(&self.context, f) 134 | } 135 | } 136 | 137 | impl StdError for ContextError 138 | where 139 | C: Display, 140 | E: StdError + 'static, 141 | { 142 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 143 | Some(&self.error) 144 | } 145 | 146 | #[cfg(error_generic_member_access)] 147 | fn provide<'a>(&'a self, request: &mut Request<'a>) { 148 | nightly::provide(&self.error, request); 149 | } 150 | } 151 | 152 | impl StdError for ContextError 153 | where 154 | C: Display, 155 | { 156 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 157 | Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) }) 158 | } 159 | 160 | #[cfg(error_generic_member_access)] 161 | fn provide<'a>(&'a self, request: &mut Request<'a>) { 162 | Error::provide(&self.error, request); 163 | } 164 | } 165 | 166 | struct Quoted(C); 167 | 168 | impl Debug for Quoted 169 | where 170 | C: Display, 171 | { 172 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 173 | formatter.write_char('"')?; 174 | Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; 175 | formatter.write_char('"')?; 176 | Ok(()) 177 | } 178 | } 179 | 180 | impl Write for Quoted<&mut fmt::Formatter<'_>> { 181 | fn write_str(&mut self, s: &str) -> fmt::Result { 182 | Display::fmt(&s.escape_debug(), self.0) 183 | } 184 | } 185 | 186 | pub(crate) mod private { 187 | use super::*; 188 | 189 | pub trait Sealed {} 190 | 191 | impl Sealed for Result where E: ext::StdError {} 192 | impl Sealed for Option {} 193 | } 194 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::backtrace::Backtrace; 2 | use crate::chain::Chain; 3 | #[cfg(error_generic_member_access)] 4 | use crate::nightly::{self, Request}; 5 | #[cfg(any(feature = "std", not(anyhow_no_core_error), anyhow_no_ptr_addr_of))] 6 | use crate::ptr::Mut; 7 | use crate::ptr::{Own, Ref}; 8 | use crate::{Error, StdError}; 9 | use alloc::boxed::Box; 10 | use core::any::TypeId; 11 | use core::fmt::{self, Debug, Display}; 12 | use core::mem::ManuallyDrop; 13 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 14 | use core::ops::{Deref, DerefMut}; 15 | #[cfg(not(anyhow_no_core_unwind_safe))] 16 | use core::panic::{RefUnwindSafe, UnwindSafe}; 17 | #[cfg(not(anyhow_no_ptr_addr_of))] 18 | use core::ptr; 19 | use core::ptr::NonNull; 20 | #[cfg(all(feature = "std", anyhow_no_core_unwind_safe))] 21 | use std::panic::{RefUnwindSafe, UnwindSafe}; 22 | 23 | impl Error { 24 | /// Create a new error object from any error type. 25 | /// 26 | /// The error type must be threadsafe and `'static`, so that the `Error` 27 | /// will be as well. 28 | /// 29 | /// If the error type does not provide a backtrace, a backtrace will be 30 | /// created here to ensure that a backtrace exists. 31 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 32 | #[cold] 33 | #[must_use] 34 | pub fn new(error: E) -> Self 35 | where 36 | E: StdError + Send + Sync + 'static, 37 | { 38 | let backtrace = backtrace_if_absent!(&error); 39 | Error::construct_from_std(error, backtrace) 40 | } 41 | 42 | /// Create a new error object from a printable error message. 43 | /// 44 | /// If the argument implements std::error::Error, prefer `Error::new` 45 | /// instead which preserves the underlying error's cause chain and 46 | /// backtrace. If the argument may or may not implement std::error::Error 47 | /// now or in the future, use `anyhow!(err)` which handles either way 48 | /// correctly. 49 | /// 50 | /// `Error::msg("...")` is equivalent to `anyhow!("...")` but occasionally 51 | /// convenient in places where a function is preferable over a macro, such 52 | /// as iterator or stream combinators: 53 | /// 54 | /// ``` 55 | /// # mod ffi { 56 | /// # pub struct Input; 57 | /// # pub struct Output; 58 | /// # pub async fn do_some_work(_: Input) -> Result { 59 | /// # unimplemented!() 60 | /// # } 61 | /// # } 62 | /// # 63 | /// # use ffi::{Input, Output}; 64 | /// # 65 | /// use anyhow::{Error, Result}; 66 | /// use futures::stream::{Stream, StreamExt, TryStreamExt}; 67 | /// 68 | /// async fn demo(stream: S) -> Result> 69 | /// where 70 | /// S: Stream, 71 | /// { 72 | /// stream 73 | /// .then(ffi::do_some_work) // returns Result 74 | /// .map_err(Error::msg) 75 | /// .try_collect() 76 | /// .await 77 | /// } 78 | /// ``` 79 | #[cold] 80 | #[must_use] 81 | pub fn msg(message: M) -> Self 82 | where 83 | M: Display + Debug + Send + Sync + 'static, 84 | { 85 | Error::construct_from_adhoc(message, backtrace!()) 86 | } 87 | 88 | /// Construct an error object from a type-erased standard library error. 89 | /// 90 | /// This is mostly useful for interop with other error libraries. 91 | /// 92 | /// # Example 93 | /// 94 | /// Here is a skeleton of a library that provides its own error abstraction. 95 | /// The pair of `From` impls provide bidirectional support for `?` 96 | /// conversion between `Report` and `anyhow::Error`. 97 | /// 98 | /// ``` 99 | /// use std::error::Error as StdError; 100 | /// 101 | /// pub struct Report {/* ... */} 102 | /// 103 | /// impl From for Report 104 | /// where 105 | /// E: Into, 106 | /// Result<(), E>: anyhow::Context<(), E>, 107 | /// { 108 | /// fn from(error: E) -> Self { 109 | /// let anyhow_error: anyhow::Error = error.into(); 110 | /// let boxed_error: Box = anyhow_error.into(); 111 | /// Report::from_boxed(boxed_error) 112 | /// } 113 | /// } 114 | /// 115 | /// impl From for anyhow::Error { 116 | /// fn from(report: Report) -> Self { 117 | /// let boxed_error: Box = report.into_boxed(); 118 | /// anyhow::Error::from_boxed(boxed_error) 119 | /// } 120 | /// } 121 | /// 122 | /// impl Report { 123 | /// fn from_boxed(boxed_error: Box) -> Self { 124 | /// todo!() 125 | /// } 126 | /// fn into_boxed(self) -> Box { 127 | /// todo!() 128 | /// } 129 | /// } 130 | /// 131 | /// // Example usage: can use `?` in both directions. 132 | /// fn a() -> anyhow::Result<()> { 133 | /// b()?; 134 | /// Ok(()) 135 | /// } 136 | /// fn b() -> Result<(), Report> { 137 | /// a()?; 138 | /// Ok(()) 139 | /// } 140 | /// ``` 141 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 142 | #[cold] 143 | #[must_use] 144 | pub fn from_boxed(boxed_error: Box) -> Self { 145 | let backtrace = backtrace_if_absent!(&*boxed_error); 146 | Error::construct_from_boxed(boxed_error, backtrace) 147 | } 148 | 149 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 150 | #[cold] 151 | pub(crate) fn construct_from_std(error: E, backtrace: Option) -> Self 152 | where 153 | E: StdError + Send + Sync + 'static, 154 | { 155 | let vtable = &ErrorVTable { 156 | object_drop: object_drop::, 157 | object_ref: object_ref::, 158 | #[cfg(anyhow_no_ptr_addr_of)] 159 | object_mut: object_mut::, 160 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 161 | object_boxed: object_boxed::, 162 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 163 | object_reallocate_boxed: object_reallocate_boxed::, 164 | object_downcast: object_downcast::, 165 | #[cfg(anyhow_no_ptr_addr_of)] 166 | object_downcast_mut: object_downcast_mut::, 167 | object_drop_rest: object_drop_front::, 168 | #[cfg(all( 169 | not(error_generic_member_access), 170 | any(std_backtrace, feature = "backtrace") 171 | ))] 172 | object_backtrace: no_backtrace, 173 | }; 174 | 175 | // Safety: passing vtable that operates on the right type E. 176 | unsafe { Error::construct(error, vtable, backtrace) } 177 | } 178 | 179 | #[cold] 180 | pub(crate) fn construct_from_adhoc(message: M, backtrace: Option) -> Self 181 | where 182 | M: Display + Debug + Send + Sync + 'static, 183 | { 184 | use crate::wrapper::MessageError; 185 | let error: MessageError = MessageError(message); 186 | let vtable = &ErrorVTable { 187 | object_drop: object_drop::>, 188 | object_ref: object_ref::>, 189 | #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] 190 | object_mut: object_mut::>, 191 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 192 | object_boxed: object_boxed::>, 193 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 194 | object_reallocate_boxed: object_reallocate_boxed::>, 195 | object_downcast: object_downcast::, 196 | #[cfg(anyhow_no_ptr_addr_of)] 197 | object_downcast_mut: object_downcast_mut::, 198 | object_drop_rest: object_drop_front::, 199 | #[cfg(all( 200 | not(error_generic_member_access), 201 | any(std_backtrace, feature = "backtrace") 202 | ))] 203 | object_backtrace: no_backtrace, 204 | }; 205 | 206 | // Safety: MessageError is repr(transparent) so it is okay for the 207 | // vtable to allow casting the MessageError to M. 208 | unsafe { Error::construct(error, vtable, backtrace) } 209 | } 210 | 211 | #[cold] 212 | pub(crate) fn construct_from_display(message: M, backtrace: Option) -> Self 213 | where 214 | M: Display + Send + Sync + 'static, 215 | { 216 | use crate::wrapper::DisplayError; 217 | let error: DisplayError = DisplayError(message); 218 | let vtable = &ErrorVTable { 219 | object_drop: object_drop::>, 220 | object_ref: object_ref::>, 221 | #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] 222 | object_mut: object_mut::>, 223 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 224 | object_boxed: object_boxed::>, 225 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 226 | object_reallocate_boxed: object_reallocate_boxed::>, 227 | object_downcast: object_downcast::, 228 | #[cfg(anyhow_no_ptr_addr_of)] 229 | object_downcast_mut: object_downcast_mut::, 230 | object_drop_rest: object_drop_front::, 231 | #[cfg(all( 232 | not(error_generic_member_access), 233 | any(std_backtrace, feature = "backtrace") 234 | ))] 235 | object_backtrace: no_backtrace, 236 | }; 237 | 238 | // Safety: DisplayError is repr(transparent) so it is okay for the 239 | // vtable to allow casting the DisplayError to M. 240 | unsafe { Error::construct(error, vtable, backtrace) } 241 | } 242 | 243 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 244 | #[cold] 245 | pub(crate) fn construct_from_context( 246 | context: C, 247 | error: E, 248 | backtrace: Option, 249 | ) -> Self 250 | where 251 | C: Display + Send + Sync + 'static, 252 | E: StdError + Send + Sync + 'static, 253 | { 254 | let error: ContextError = ContextError { context, error }; 255 | 256 | let vtable = &ErrorVTable { 257 | object_drop: object_drop::>, 258 | object_ref: object_ref::>, 259 | #[cfg(anyhow_no_ptr_addr_of)] 260 | object_mut: object_mut::>, 261 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 262 | object_boxed: object_boxed::>, 263 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 264 | object_reallocate_boxed: object_reallocate_boxed::>, 265 | object_downcast: context_downcast::, 266 | #[cfg(anyhow_no_ptr_addr_of)] 267 | object_downcast_mut: context_downcast_mut::, 268 | object_drop_rest: context_drop_rest::, 269 | #[cfg(all( 270 | not(error_generic_member_access), 271 | any(std_backtrace, feature = "backtrace") 272 | ))] 273 | object_backtrace: no_backtrace, 274 | }; 275 | 276 | // Safety: passing vtable that operates on the right type. 277 | unsafe { Error::construct(error, vtable, backtrace) } 278 | } 279 | 280 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 281 | #[cold] 282 | pub(crate) fn construct_from_boxed( 283 | error: Box, 284 | backtrace: Option, 285 | ) -> Self { 286 | use crate::wrapper::BoxedError; 287 | let error = BoxedError(error); 288 | let vtable = &ErrorVTable { 289 | object_drop: object_drop::, 290 | object_ref: object_ref::, 291 | #[cfg(anyhow_no_ptr_addr_of)] 292 | object_mut: object_mut::, 293 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 294 | object_boxed: object_boxed::, 295 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 296 | object_reallocate_boxed: object_reallocate_boxed::, 297 | object_downcast: object_downcast::>, 298 | #[cfg(anyhow_no_ptr_addr_of)] 299 | object_downcast_mut: object_downcast_mut::>, 300 | object_drop_rest: object_drop_front::>, 301 | #[cfg(all( 302 | not(error_generic_member_access), 303 | any(std_backtrace, feature = "backtrace") 304 | ))] 305 | object_backtrace: no_backtrace, 306 | }; 307 | 308 | // Safety: BoxedError is repr(transparent) so it is okay for the vtable 309 | // to allow casting to Box. 310 | unsafe { Error::construct(error, vtable, backtrace) } 311 | } 312 | 313 | // Takes backtrace as argument rather than capturing it here so that the 314 | // user sees one fewer layer of wrapping noise in the backtrace. 315 | // 316 | // Unsafe because the given vtable must have sensible behavior on the error 317 | // value of type E. 318 | #[cold] 319 | unsafe fn construct( 320 | error: E, 321 | vtable: &'static ErrorVTable, 322 | backtrace: Option, 323 | ) -> Self 324 | where 325 | E: StdError + Send + Sync + 'static, 326 | { 327 | let inner: Box> = Box::new(ErrorImpl { 328 | vtable, 329 | backtrace, 330 | _object: error, 331 | }); 332 | // Erase the concrete type of E from the compile-time type system. This 333 | // is equivalent to the safe unsize coercion from Box> to 334 | // Box> except that the 335 | // result is a thin pointer. The necessary behavior for manipulating the 336 | // underlying ErrorImpl is preserved in the vtable provided by the 337 | // caller rather than a builtin fat pointer vtable. 338 | let inner = Own::new(inner).cast::(); 339 | Error { inner } 340 | } 341 | 342 | /// Wrap the error value with additional context. 343 | /// 344 | /// For attaching context to a `Result` as it is propagated, the 345 | /// [`Context`][crate::Context] extension trait may be more convenient than 346 | /// this function. 347 | /// 348 | /// The primary reason to use `error.context(...)` instead of 349 | /// `result.context(...)` via the `Context` trait would be if the context 350 | /// needs to depend on some data held by the underlying error: 351 | /// 352 | /// ``` 353 | /// # use std::fmt::{self, Debug, Display}; 354 | /// # 355 | /// # type T = (); 356 | /// # 357 | /// # impl std::error::Error for ParseError {} 358 | /// # impl Debug for ParseError { 359 | /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 360 | /// # unimplemented!() 361 | /// # } 362 | /// # } 363 | /// # impl Display for ParseError { 364 | /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 365 | /// # unimplemented!() 366 | /// # } 367 | /// # } 368 | /// # 369 | /// use anyhow::Result; 370 | /// use std::fs::File; 371 | /// use std::path::Path; 372 | /// 373 | /// struct ParseError { 374 | /// line: usize, 375 | /// column: usize, 376 | /// } 377 | /// 378 | /// fn parse_impl(file: File) -> Result { 379 | /// # const IGNORE: &str = stringify! { 380 | /// ... 381 | /// # }; 382 | /// # unimplemented!() 383 | /// } 384 | /// 385 | /// pub fn parse(path: impl AsRef) -> Result { 386 | /// let file = File::open(&path)?; 387 | /// parse_impl(file).map_err(|error| { 388 | /// let context = format!( 389 | /// "only the first {} lines of {} are valid", 390 | /// error.line, path.as_ref().display(), 391 | /// ); 392 | /// anyhow::Error::new(error).context(context) 393 | /// }) 394 | /// } 395 | /// ``` 396 | #[cold] 397 | #[must_use] 398 | pub fn context(self, context: C) -> Self 399 | where 400 | C: Display + Send + Sync + 'static, 401 | { 402 | let error: ContextError = ContextError { 403 | context, 404 | error: self, 405 | }; 406 | 407 | let vtable = &ErrorVTable { 408 | object_drop: object_drop::>, 409 | object_ref: object_ref::>, 410 | #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] 411 | object_mut: object_mut::>, 412 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 413 | object_boxed: object_boxed::>, 414 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 415 | object_reallocate_boxed: object_reallocate_boxed::>, 416 | object_downcast: context_chain_downcast::, 417 | #[cfg(anyhow_no_ptr_addr_of)] 418 | object_downcast_mut: context_chain_downcast_mut::, 419 | object_drop_rest: context_chain_drop_rest::, 420 | #[cfg(all( 421 | not(error_generic_member_access), 422 | any(std_backtrace, feature = "backtrace") 423 | ))] 424 | object_backtrace: context_backtrace::, 425 | }; 426 | 427 | // As the cause is anyhow::Error, we already have a backtrace for it. 428 | let backtrace = None; 429 | 430 | // Safety: passing vtable that operates on the right type. 431 | unsafe { Error::construct(error, vtable, backtrace) } 432 | } 433 | 434 | /// Get the backtrace for this Error. 435 | /// 436 | /// In order for the backtrace to be meaningful, one of the two environment 437 | /// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined 438 | /// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat 439 | /// expensive to capture in Rust, so we don't necessarily want to be 440 | /// capturing them all over the place all the time. 441 | /// 442 | /// - If you want panics and errors to both have backtraces, set 443 | /// `RUST_BACKTRACE=1`; 444 | /// - If you want only errors to have backtraces, set 445 | /// `RUST_LIB_BACKTRACE=1`; 446 | /// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and 447 | /// `RUST_LIB_BACKTRACE=0`. 448 | /// 449 | /// # Stability 450 | /// 451 | /// Standard library backtraces are only available when using Rust ≥ 452 | /// 1.65. On older compilers, this function is only available if the crate's 453 | /// "backtrace" feature is enabled, and will use the `backtrace` crate as 454 | /// the underlying backtrace implementation. The return type of this 455 | /// function on old compilers is `&(impl Debug + Display)`. 456 | /// 457 | /// ```toml 458 | /// [dependencies] 459 | /// anyhow = { version = "1.0", features = ["backtrace"] } 460 | /// ``` 461 | #[cfg(any(std_backtrace, feature = "backtrace"))] 462 | pub fn backtrace(&self) -> &impl_backtrace!() { 463 | unsafe { ErrorImpl::backtrace(self.inner.by_ref()) } 464 | } 465 | 466 | /// An iterator of the chain of source errors contained by this Error. 467 | /// 468 | /// This iterator will visit every error in the cause chain of this error 469 | /// object, beginning with the error that this error object was created 470 | /// from. 471 | /// 472 | /// # Example 473 | /// 474 | /// ``` 475 | /// use anyhow::Error; 476 | /// use std::io; 477 | /// 478 | /// pub fn underlying_io_error_kind(error: &Error) -> Option { 479 | /// for cause in error.chain() { 480 | /// if let Some(io_error) = cause.downcast_ref::() { 481 | /// return Some(io_error.kind()); 482 | /// } 483 | /// } 484 | /// None 485 | /// } 486 | /// ``` 487 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 488 | #[cold] 489 | pub fn chain(&self) -> Chain { 490 | unsafe { ErrorImpl::chain(self.inner.by_ref()) } 491 | } 492 | 493 | /// The lowest level cause of this error — this error's cause's 494 | /// cause's cause etc. 495 | /// 496 | /// The root cause is the last error in the iterator produced by 497 | /// [`chain()`][Error::chain]. 498 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 499 | #[allow(clippy::double_ended_iterator_last)] 500 | pub fn root_cause(&self) -> &(dyn StdError + 'static) { 501 | self.chain().last().unwrap() 502 | } 503 | 504 | /// Returns true if `E` is the type held by this error object. 505 | /// 506 | /// For errors with context, this method returns true if `E` matches the 507 | /// type of the context `C` **or** the type of the error on which the 508 | /// context has been attached. For details about the interaction between 509 | /// context and downcasting, [see here]. 510 | /// 511 | /// [see here]: crate::Context#effect-on-downcasting 512 | pub fn is(&self) -> bool 513 | where 514 | E: Display + Debug + Send + Sync + 'static, 515 | { 516 | self.downcast_ref::().is_some() 517 | } 518 | 519 | /// Attempt to downcast the error object to a concrete type. 520 | pub fn downcast(mut self) -> Result 521 | where 522 | E: Display + Debug + Send + Sync + 'static, 523 | { 524 | let target = TypeId::of::(); 525 | let inner = self.inner.by_mut(); 526 | unsafe { 527 | // Use vtable to find NonNull<()> which points to a value of type E 528 | // somewhere inside the data structure. 529 | #[cfg(not(anyhow_no_ptr_addr_of))] 530 | let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) { 531 | Some(addr) => addr.by_mut().extend(), 532 | None => return Err(self), 533 | }; 534 | #[cfg(anyhow_no_ptr_addr_of)] 535 | let addr = match (vtable(inner.ptr).object_downcast_mut)(inner, target) { 536 | Some(addr) => addr.extend(), 537 | None => return Err(self), 538 | }; 539 | 540 | // Prepare to read E out of the data structure. We'll drop the rest 541 | // of the data structure separately so that E is not dropped. 542 | let outer = ManuallyDrop::new(self); 543 | 544 | // Read E from where the vtable found it. 545 | let error = addr.cast::().read(); 546 | 547 | // Drop rest of the data structure outside of E. 548 | (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target); 549 | 550 | Ok(error) 551 | } 552 | } 553 | 554 | /// Downcast this error object by reference. 555 | /// 556 | /// # Example 557 | /// 558 | /// ``` 559 | /// # use anyhow::anyhow; 560 | /// # use std::fmt::{self, Display}; 561 | /// # use std::task::Poll; 562 | /// # 563 | /// # #[derive(Debug)] 564 | /// # enum DataStoreError { 565 | /// # Censored(()), 566 | /// # } 567 | /// # 568 | /// # impl Display for DataStoreError { 569 | /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 570 | /// # unimplemented!() 571 | /// # } 572 | /// # } 573 | /// # 574 | /// # impl std::error::Error for DataStoreError {} 575 | /// # 576 | /// # const REDACTED_CONTENT: () = (); 577 | /// # 578 | /// # let error = anyhow!("..."); 579 | /// # let root_cause = &error; 580 | /// # 581 | /// # let ret = 582 | /// // If the error was caused by redaction, then return a tombstone instead 583 | /// // of the content. 584 | /// match root_cause.downcast_ref::() { 585 | /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), 586 | /// None => Err(error), 587 | /// } 588 | /// # ; 589 | /// ``` 590 | pub fn downcast_ref(&self) -> Option<&E> 591 | where 592 | E: Display + Debug + Send + Sync + 'static, 593 | { 594 | let target = TypeId::of::(); 595 | unsafe { 596 | // Use vtable to find NonNull<()> which points to a value of type E 597 | // somewhere inside the data structure. 598 | let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?; 599 | Some(addr.cast::().deref()) 600 | } 601 | } 602 | 603 | /// Downcast this error object by mutable reference. 604 | pub fn downcast_mut(&mut self) -> Option<&mut E> 605 | where 606 | E: Display + Debug + Send + Sync + 'static, 607 | { 608 | let target = TypeId::of::(); 609 | unsafe { 610 | // Use vtable to find NonNull<()> which points to a value of type E 611 | // somewhere inside the data structure. 612 | 613 | #[cfg(not(anyhow_no_ptr_addr_of))] 614 | let addr = 615 | (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut(); 616 | 617 | #[cfg(anyhow_no_ptr_addr_of)] 618 | let addr = (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target)?; 619 | 620 | Some(addr.cast::().deref_mut()) 621 | } 622 | } 623 | 624 | /// Convert to a standard library error trait object. 625 | /// 626 | /// This is implemented as a cheap pointer cast that does not allocate or 627 | /// deallocate memory. Like [`anyhow::Error::from_boxed`], it's useful for 628 | /// interop with other error libraries. 629 | /// 630 | /// The same conversion is also available as 631 | /// impl From<anyhow::Error> 632 | /// for Box<dyn Error + Send + Sync + 'static>. 633 | /// 634 | /// If a backtrace was collected during construction of the `anyhow::Error`, 635 | /// that backtrace remains accessible using the standard library `Error` 636 | /// trait's provider API, but as a consequence, the resulting boxed error 637 | /// can no longer be downcast to its original underlying type. 638 | /// 639 | /// ``` 640 | #[cfg_attr(not(error_generic_member_access), doc = "# _ = stringify! {")] 641 | /// #![feature(error_generic_member_access)] 642 | /// 643 | /// use anyhow::anyhow; 644 | /// use std::backtrace::Backtrace; 645 | /// use thiserror::Error; 646 | /// 647 | /// #[derive(Error, Debug)] 648 | /// #[error("...")] 649 | /// struct MyError; 650 | /// 651 | /// let anyhow_error = anyhow!(MyError); 652 | /// println!("{}", anyhow_error.backtrace()); // has Backtrace 653 | /// assert!(anyhow_error.downcast_ref::().is_some()); // can downcast 654 | /// 655 | /// let boxed_dyn_error = anyhow_error.into_boxed_dyn_error(); 656 | /// assert!(std::error::request_ref::(&*boxed_dyn_error).is_some()); // has Backtrace 657 | /// assert!(boxed_dyn_error.downcast_ref::().is_none()); // can no longer downcast 658 | #[cfg_attr(not(error_generic_member_access), doc = "# };")] 659 | /// ``` 660 | /// 661 | /// [`anyhow::Error::from_boxed`]: Self::from_boxed 662 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 663 | #[must_use] 664 | pub fn into_boxed_dyn_error(self) -> Box { 665 | let outer = ManuallyDrop::new(self); 666 | unsafe { 667 | // Use vtable to attach ErrorImpl's native StdError vtable for 668 | // the right original type E. 669 | (vtable(outer.inner.ptr).object_boxed)(outer.inner) 670 | } 671 | } 672 | 673 | /// Convert to a standard library error trait object. 674 | /// 675 | /// Unlike `self.into_boxed_dyn_error()`, this method relocates the 676 | /// underlying error into a new allocation in order to make it downcastable 677 | /// to `&E` or `Box` for its original underlying error type. Any 678 | /// backtrace collected during construction of the `anyhow::Error` is 679 | /// discarded. 680 | /// 681 | /// ``` 682 | #[cfg_attr(not(error_generic_member_access), doc = "# _ = stringify!{")] 683 | /// #![feature(error_generic_member_access)] 684 | /// 685 | /// use anyhow::anyhow; 686 | /// use std::backtrace::Backtrace; 687 | /// use thiserror::Error; 688 | /// 689 | /// #[derive(Error, Debug)] 690 | /// #[error("...")] 691 | /// struct MyError; 692 | /// 693 | /// let anyhow_error = anyhow!(MyError); 694 | /// println!("{}", anyhow_error.backtrace()); // has Backtrace 695 | /// assert!(anyhow_error.downcast_ref::().is_some()); // can downcast 696 | /// 697 | /// let boxed_dyn_error = anyhow_error.reallocate_into_boxed_dyn_error_without_backtrace(); 698 | /// assert!(std::error::request_ref::(&*boxed_dyn_error).is_none()); // Backtrace lost 699 | /// assert!(boxed_dyn_error.downcast_ref::().is_some()); // can downcast to &MyError 700 | /// assert!(boxed_dyn_error.downcast::().is_ok()); // can downcast to Box 701 | #[cfg_attr(not(error_generic_member_access), doc = "# };")] 702 | /// ``` 703 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 704 | #[must_use] 705 | pub fn reallocate_into_boxed_dyn_error_without_backtrace( 706 | self, 707 | ) -> Box { 708 | let outer = ManuallyDrop::new(self); 709 | unsafe { 710 | // Use vtable to attach E's native StdError vtable for the right 711 | // original type E. 712 | (vtable(outer.inner.ptr).object_reallocate_boxed)(outer.inner) 713 | } 714 | } 715 | 716 | #[cfg(error_generic_member_access)] 717 | pub(crate) fn provide<'a>(&'a self, request: &mut Request<'a>) { 718 | unsafe { ErrorImpl::provide(self.inner.by_ref(), request) } 719 | } 720 | 721 | // Called by thiserror when you have `#[source] anyhow::Error`. This provide 722 | // implementation includes the anyhow::Error's Backtrace if any, unlike 723 | // deref'ing to dyn Error where the provide implementation would include 724 | // only the original error's Backtrace from before it got wrapped into an 725 | // anyhow::Error. 726 | #[cfg(error_generic_member_access)] 727 | #[doc(hidden)] 728 | pub fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) { 729 | Self::provide(self, request); 730 | } 731 | } 732 | 733 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 734 | impl From for Error 735 | where 736 | E: StdError + Send + Sync + 'static, 737 | { 738 | #[cold] 739 | fn from(error: E) -> Self { 740 | let backtrace = backtrace_if_absent!(&error); 741 | Error::construct_from_std(error, backtrace) 742 | } 743 | } 744 | 745 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 746 | impl Deref for Error { 747 | type Target = dyn StdError + Send + Sync + 'static; 748 | 749 | fn deref(&self) -> &Self::Target { 750 | unsafe { ErrorImpl::error(self.inner.by_ref()) } 751 | } 752 | } 753 | 754 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 755 | impl DerefMut for Error { 756 | fn deref_mut(&mut self) -> &mut Self::Target { 757 | unsafe { ErrorImpl::error_mut(self.inner.by_mut()) } 758 | } 759 | } 760 | 761 | impl Display for Error { 762 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 763 | unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) } 764 | } 765 | } 766 | 767 | impl Debug for Error { 768 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 769 | unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) } 770 | } 771 | } 772 | 773 | impl Drop for Error { 774 | fn drop(&mut self) { 775 | unsafe { 776 | // Invoke the vtable's drop behavior. 777 | (vtable(self.inner.ptr).object_drop)(self.inner); 778 | } 779 | } 780 | } 781 | 782 | struct ErrorVTable { 783 | object_drop: unsafe fn(Own), 784 | object_ref: unsafe fn(Ref) -> Ref, 785 | #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] 786 | object_mut: unsafe fn(Mut) -> &mut (dyn StdError + Send + Sync + 'static), 787 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 788 | object_boxed: unsafe fn(Own) -> Box, 789 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 790 | object_reallocate_boxed: unsafe fn(Own) -> Box, 791 | object_downcast: unsafe fn(Ref, TypeId) -> Option>, 792 | #[cfg(anyhow_no_ptr_addr_of)] 793 | object_downcast_mut: unsafe fn(Mut, TypeId) -> Option>, 794 | object_drop_rest: unsafe fn(Own, TypeId), 795 | #[cfg(all( 796 | not(error_generic_member_access), 797 | any(std_backtrace, feature = "backtrace") 798 | ))] 799 | object_backtrace: unsafe fn(Ref) -> Option<&Backtrace>, 800 | } 801 | 802 | // Safety: requires layout of *e to match ErrorImpl. 803 | unsafe fn object_drop(e: Own) { 804 | // Cast back to ErrorImpl so that the allocator receives the correct 805 | // Layout to deallocate the Box's memory. 806 | let unerased_own = e.cast::>(); 807 | drop(unsafe { unerased_own.boxed() }); 808 | } 809 | 810 | // Safety: requires layout of *e to match ErrorImpl. 811 | unsafe fn object_drop_front(e: Own, target: TypeId) { 812 | // Drop the fields of ErrorImpl other than E as well as the Box allocation, 813 | // without dropping E itself. This is used by downcast after doing a 814 | // ptr::read to take ownership of the E. 815 | let _ = target; 816 | let unerased_own = e.cast::>>(); 817 | drop(unsafe { unerased_own.boxed() }); 818 | } 819 | 820 | // Safety: requires layout of *e to match ErrorImpl. 821 | unsafe fn object_ref(e: Ref) -> Ref 822 | where 823 | E: StdError + Send + Sync + 'static, 824 | { 825 | // Attach E's native StdError vtable onto a pointer to self._object. 826 | 827 | let unerased_ref = e.cast::>(); 828 | 829 | #[cfg(not(anyhow_no_ptr_addr_of))] 830 | return Ref::from_raw(unsafe { 831 | NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E) 832 | }); 833 | 834 | #[cfg(anyhow_no_ptr_addr_of)] 835 | return Ref::new(unsafe { &unerased_ref.deref()._object }); 836 | } 837 | 838 | // Safety: requires layout of *e to match ErrorImpl, and for `e` to be derived 839 | // from a `&mut` 840 | #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] 841 | unsafe fn object_mut(e: Mut) -> &mut (dyn StdError + Send + Sync + 'static) 842 | where 843 | E: StdError + Send + Sync + 'static, 844 | { 845 | // Attach E's native StdError vtable onto a pointer to self._object. 846 | let unerased_mut = e.cast::>(); 847 | unsafe { &mut unerased_mut.deref_mut()._object } 848 | } 849 | 850 | // Safety: requires layout of *e to match ErrorImpl. 851 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 852 | unsafe fn object_boxed(e: Own) -> Box 853 | where 854 | E: StdError + Send + Sync + 'static, 855 | { 856 | // Attach ErrorImpl's native StdError vtable. The StdError impl is below. 857 | let unerased_own = e.cast::>(); 858 | unsafe { unerased_own.boxed() } 859 | } 860 | 861 | // Safety: requires layout of *e to match ErrorImpl. 862 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 863 | unsafe fn object_reallocate_boxed(e: Own) -> Box 864 | where 865 | E: StdError + Send + Sync + 'static, 866 | { 867 | // Attach E's native StdError vtable. 868 | let unerased_own = e.cast::>(); 869 | Box::new(unsafe { unerased_own.boxed() }._object) 870 | } 871 | 872 | // Safety: requires layout of *e to match ErrorImpl. 873 | unsafe fn object_downcast(e: Ref, target: TypeId) -> Option> 874 | where 875 | E: 'static, 876 | { 877 | if TypeId::of::() == target { 878 | // Caller is looking for an E pointer and e is ErrorImpl, take a 879 | // pointer to its E field. 880 | 881 | let unerased_ref = e.cast::>(); 882 | 883 | #[cfg(not(anyhow_no_ptr_addr_of))] 884 | return Some( 885 | Ref::from_raw(unsafe { 886 | NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E) 887 | }) 888 | .cast::<()>(), 889 | ); 890 | 891 | #[cfg(anyhow_no_ptr_addr_of)] 892 | return Some(Ref::new(unsafe { &unerased_ref.deref()._object }).cast::<()>()); 893 | } else { 894 | None 895 | } 896 | } 897 | 898 | // Safety: requires layout of *e to match ErrorImpl. 899 | #[cfg(anyhow_no_ptr_addr_of)] 900 | unsafe fn object_downcast_mut(e: Mut, target: TypeId) -> Option> 901 | where 902 | E: 'static, 903 | { 904 | if TypeId::of::() == target { 905 | // Caller is looking for an E pointer and e is ErrorImpl, take a 906 | // pointer to its E field. 907 | let unerased_mut = e.cast::>(); 908 | let unerased = unsafe { unerased_mut.deref_mut() }; 909 | Some(Mut::new(&mut unerased._object).cast::<()>()) 910 | } else { 911 | None 912 | } 913 | } 914 | 915 | #[cfg(all( 916 | not(error_generic_member_access), 917 | any(std_backtrace, feature = "backtrace") 918 | ))] 919 | fn no_backtrace(e: Ref) -> Option<&Backtrace> { 920 | let _ = e; 921 | None 922 | } 923 | 924 | // Safety: requires layout of *e to match ErrorImpl>. 925 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 926 | unsafe fn context_downcast(e: Ref, target: TypeId) -> Option> 927 | where 928 | C: 'static, 929 | E: 'static, 930 | { 931 | if TypeId::of::() == target { 932 | let unerased_ref = e.cast::>>(); 933 | let unerased = unsafe { unerased_ref.deref() }; 934 | Some(Ref::new(&unerased._object.context).cast::<()>()) 935 | } else if TypeId::of::() == target { 936 | let unerased_ref = e.cast::>>(); 937 | let unerased = unsafe { unerased_ref.deref() }; 938 | Some(Ref::new(&unerased._object.error).cast::<()>()) 939 | } else { 940 | None 941 | } 942 | } 943 | 944 | // Safety: requires layout of *e to match ErrorImpl>. 945 | #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] 946 | unsafe fn context_downcast_mut(e: Mut, target: TypeId) -> Option> 947 | where 948 | C: 'static, 949 | E: 'static, 950 | { 951 | if TypeId::of::() == target { 952 | let unerased_mut = e.cast::>>(); 953 | let unerased = unsafe { unerased_mut.deref_mut() }; 954 | Some(Mut::new(&mut unerased._object.context).cast::<()>()) 955 | } else if TypeId::of::() == target { 956 | let unerased_mut = e.cast::>>(); 957 | let unerased = unsafe { unerased_mut.deref_mut() }; 958 | Some(Mut::new(&mut unerased._object.error).cast::<()>()) 959 | } else { 960 | None 961 | } 962 | } 963 | 964 | // Safety: requires layout of *e to match ErrorImpl>. 965 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 966 | unsafe fn context_drop_rest(e: Own, target: TypeId) 967 | where 968 | C: 'static, 969 | E: 'static, 970 | { 971 | // Called after downcasting by value to either the C or the E and doing a 972 | // ptr::read to take ownership of that value. 973 | if TypeId::of::() == target { 974 | let unerased_own = e.cast::, E>>>(); 975 | drop(unsafe { unerased_own.boxed() }); 976 | } else { 977 | let unerased_own = e.cast::>>>(); 978 | drop(unsafe { unerased_own.boxed() }); 979 | } 980 | } 981 | 982 | // Safety: requires layout of *e to match ErrorImpl>. 983 | unsafe fn context_chain_downcast(e: Ref, target: TypeId) -> Option> 984 | where 985 | C: 'static, 986 | { 987 | let unerased_ref = e.cast::>>(); 988 | let unerased = unsafe { unerased_ref.deref() }; 989 | if TypeId::of::() == target { 990 | Some(Ref::new(&unerased._object.context).cast::<()>()) 991 | } else { 992 | // Recurse down the context chain per the inner error's vtable. 993 | let source = &unerased._object.error; 994 | unsafe { (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) } 995 | } 996 | } 997 | 998 | // Safety: requires layout of *e to match ErrorImpl>. 999 | #[cfg(anyhow_no_ptr_addr_of)] 1000 | unsafe fn context_chain_downcast_mut(e: Mut, target: TypeId) -> Option> 1001 | where 1002 | C: 'static, 1003 | { 1004 | let unerased_mut = e.cast::>>(); 1005 | let unerased = unsafe { unerased_mut.deref_mut() }; 1006 | if TypeId::of::() == target { 1007 | Some(Mut::new(&mut unerased._object.context).cast::<()>()) 1008 | } else { 1009 | // Recurse down the context chain per the inner error's vtable. 1010 | let source = &mut unerased._object.error; 1011 | unsafe { (vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target) } 1012 | } 1013 | } 1014 | 1015 | // Safety: requires layout of *e to match ErrorImpl>. 1016 | unsafe fn context_chain_drop_rest(e: Own, target: TypeId) 1017 | where 1018 | C: 'static, 1019 | { 1020 | // Called after downcasting by value to either the C or one of the causes 1021 | // and doing a ptr::read to take ownership of that value. 1022 | if TypeId::of::() == target { 1023 | let unerased_own = e.cast::, Error>>>(); 1024 | // Drop the entire rest of the data structure rooted in the next Error. 1025 | drop(unsafe { unerased_own.boxed() }); 1026 | } else { 1027 | let unerased_own = e.cast::>>>(); 1028 | let unerased = unsafe { unerased_own.boxed() }; 1029 | // Read the Own from the next error. 1030 | let inner = unerased._object.error.inner; 1031 | drop(unerased); 1032 | let vtable = unsafe { vtable(inner.ptr) }; 1033 | // Recursively drop the next error using the same target typeid. 1034 | unsafe { (vtable.object_drop_rest)(inner, target) }; 1035 | } 1036 | } 1037 | 1038 | // Safety: requires layout of *e to match ErrorImpl>. 1039 | #[cfg(all( 1040 | not(error_generic_member_access), 1041 | any(std_backtrace, feature = "backtrace") 1042 | ))] 1043 | #[allow(clippy::unnecessary_wraps)] 1044 | unsafe fn context_backtrace(e: Ref) -> Option<&Backtrace> 1045 | where 1046 | C: 'static, 1047 | { 1048 | let unerased_ref = e.cast::>>(); 1049 | let unerased = unsafe { unerased_ref.deref() }; 1050 | let backtrace = unsafe { ErrorImpl::backtrace(unerased._object.error.inner.by_ref()) }; 1051 | Some(backtrace) 1052 | } 1053 | 1054 | // NOTE: If working with `ErrorImpl<()>`, references should be avoided in favor 1055 | // of raw pointers and `NonNull`. 1056 | // repr C to ensure that E remains in the final position. 1057 | #[repr(C)] 1058 | pub(crate) struct ErrorImpl { 1059 | vtable: &'static ErrorVTable, 1060 | backtrace: Option, 1061 | // NOTE: Don't use directly. Use only through vtable. Erased type may have 1062 | // different alignment. 1063 | _object: E, 1064 | } 1065 | 1066 | // Reads the vtable out of `p`. This is the same as `p.as_ref().vtable`, but 1067 | // avoids converting `p` into a reference. 1068 | unsafe fn vtable(p: NonNull) -> &'static ErrorVTable { 1069 | // NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl. 1070 | unsafe { *(p.as_ptr() as *const &'static ErrorVTable) } 1071 | } 1072 | 1073 | // repr C to ensure that ContextError has the same layout as 1074 | // ContextError, E> and ContextError>. 1075 | #[repr(C)] 1076 | pub(crate) struct ContextError { 1077 | pub context: C, 1078 | pub error: E, 1079 | } 1080 | 1081 | impl ErrorImpl { 1082 | fn erase(&self) -> Ref { 1083 | // Erase the concrete type of E but preserve the vtable in self.vtable 1084 | // for manipulating the resulting thin pointer. This is analogous to an 1085 | // unsize coercion. 1086 | Ref::new(self).cast::() 1087 | } 1088 | } 1089 | 1090 | impl ErrorImpl { 1091 | pub(crate) unsafe fn error(this: Ref) -> &(dyn StdError + Send + Sync + 'static) { 1092 | // Use vtable to attach E's native StdError vtable for the right 1093 | // original type E. 1094 | unsafe { (vtable(this.ptr).object_ref)(this).deref() } 1095 | } 1096 | 1097 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1098 | pub(crate) unsafe fn error_mut(this: Mut) -> &mut (dyn StdError + Send + Sync + 'static) { 1099 | // Use vtable to attach E's native StdError vtable for the right 1100 | // original type E. 1101 | 1102 | #[cfg(not(anyhow_no_ptr_addr_of))] 1103 | return unsafe { 1104 | (vtable(this.ptr).object_ref)(this.by_ref()) 1105 | .by_mut() 1106 | .deref_mut() 1107 | }; 1108 | 1109 | #[cfg(anyhow_no_ptr_addr_of)] 1110 | return unsafe { (vtable(this.ptr).object_mut)(this) }; 1111 | } 1112 | 1113 | #[cfg(any(std_backtrace, feature = "backtrace"))] 1114 | pub(crate) unsafe fn backtrace(this: Ref) -> &Backtrace { 1115 | // This unwrap can only panic if the underlying error's backtrace method 1116 | // is nondeterministic, which would only happen in maliciously 1117 | // constructed code. 1118 | unsafe { this.deref() } 1119 | .backtrace 1120 | .as_ref() 1121 | .or_else(|| { 1122 | #[cfg(error_generic_member_access)] 1123 | return nightly::request_ref_backtrace(unsafe { Self::error(this) }); 1124 | #[cfg(not(error_generic_member_access))] 1125 | return unsafe { (vtable(this.ptr).object_backtrace)(this) }; 1126 | }) 1127 | .expect("backtrace capture failed") 1128 | } 1129 | 1130 | #[cfg(error_generic_member_access)] 1131 | unsafe fn provide<'a>(this: Ref<'a, Self>, request: &mut Request<'a>) { 1132 | if let Some(backtrace) = unsafe { &this.deref().backtrace } { 1133 | nightly::provide_ref_backtrace(request, backtrace); 1134 | } 1135 | nightly::provide(unsafe { Self::error(this) }, request); 1136 | } 1137 | 1138 | #[cold] 1139 | pub(crate) unsafe fn chain(this: Ref) -> Chain { 1140 | Chain::new(unsafe { Self::error(this) }) 1141 | } 1142 | } 1143 | 1144 | impl StdError for ErrorImpl 1145 | where 1146 | E: StdError, 1147 | { 1148 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 1149 | unsafe { ErrorImpl::error(self.erase()).source() } 1150 | } 1151 | 1152 | #[cfg(error_generic_member_access)] 1153 | fn provide<'a>(&'a self, request: &mut Request<'a>) { 1154 | unsafe { ErrorImpl::provide(self.erase(), request) } 1155 | } 1156 | } 1157 | 1158 | impl Debug for ErrorImpl 1159 | where 1160 | E: Debug, 1161 | { 1162 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 1163 | unsafe { ErrorImpl::debug(self.erase(), formatter) } 1164 | } 1165 | } 1166 | 1167 | impl Display for ErrorImpl 1168 | where 1169 | E: Display, 1170 | { 1171 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 1172 | unsafe { Display::fmt(ErrorImpl::error(self.erase()), formatter) } 1173 | } 1174 | } 1175 | 1176 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1177 | impl From for Box { 1178 | #[cold] 1179 | fn from(error: Error) -> Self { 1180 | error.into_boxed_dyn_error() 1181 | } 1182 | } 1183 | 1184 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1185 | impl From for Box { 1186 | #[cold] 1187 | fn from(error: Error) -> Self { 1188 | error.into_boxed_dyn_error() 1189 | } 1190 | } 1191 | 1192 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1193 | impl From for Box { 1194 | #[cold] 1195 | fn from(error: Error) -> Self { 1196 | error.into_boxed_dyn_error() 1197 | } 1198 | } 1199 | 1200 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1201 | impl AsRef for Error { 1202 | fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { 1203 | &**self 1204 | } 1205 | } 1206 | 1207 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 1208 | impl AsRef for Error { 1209 | fn as_ref(&self) -> &(dyn StdError + 'static) { 1210 | &**self 1211 | } 1212 | } 1213 | 1214 | #[cfg(any(feature = "std", not(anyhow_no_core_unwind_safe)))] 1215 | impl UnwindSafe for Error {} 1216 | 1217 | #[cfg(any(feature = "std", not(anyhow_no_core_unwind_safe)))] 1218 | impl RefUnwindSafe for Error {} 1219 | -------------------------------------------------------------------------------- /src/fmt.rs: -------------------------------------------------------------------------------- 1 | use crate::chain::Chain; 2 | use crate::error::ErrorImpl; 3 | use crate::ptr::Ref; 4 | use core::fmt::{self, Debug, Write}; 5 | 6 | impl ErrorImpl { 7 | pub(crate) unsafe fn display(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { 8 | write!(f, "{}", unsafe { Self::error(this) })?; 9 | 10 | if f.alternate() { 11 | let chain = unsafe { Self::chain(this) }; 12 | for cause in chain.skip(1) { 13 | write!(f, ": {}", cause)?; 14 | } 15 | } 16 | 17 | Ok(()) 18 | } 19 | 20 | pub(crate) unsafe fn debug(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { 21 | let error = unsafe { Self::error(this) }; 22 | 23 | if f.alternate() { 24 | return Debug::fmt(error, f); 25 | } 26 | 27 | write!(f, "{}", error)?; 28 | 29 | if let Some(cause) = error.source() { 30 | write!(f, "\n\nCaused by:")?; 31 | let multiple = cause.source().is_some(); 32 | for (n, error) in Chain::new(cause).enumerate() { 33 | writeln!(f)?; 34 | let mut indented = Indented { 35 | inner: f, 36 | number: if multiple { Some(n) } else { None }, 37 | started: false, 38 | }; 39 | write!(indented, "{}", error)?; 40 | } 41 | } 42 | 43 | #[cfg(any(std_backtrace, feature = "backtrace"))] 44 | { 45 | use crate::backtrace::BacktraceStatus; 46 | use alloc::string::ToString; 47 | 48 | let backtrace = unsafe { Self::backtrace(this) }; 49 | if let BacktraceStatus::Captured = backtrace.status() { 50 | let mut backtrace = backtrace.to_string(); 51 | write!(f, "\n\n")?; 52 | if backtrace.starts_with("stack backtrace:") { 53 | // Capitalize to match "Caused by:" 54 | backtrace.replace_range(0..1, "S"); 55 | } else { 56 | // "stack backtrace:" prefix was removed in 57 | // https://github.com/rust-lang/backtrace-rs/pull/286 58 | writeln!(f, "Stack backtrace:")?; 59 | } 60 | backtrace.truncate(backtrace.trim_end().len()); 61 | write!(f, "{}", backtrace)?; 62 | } 63 | } 64 | 65 | Ok(()) 66 | } 67 | } 68 | 69 | struct Indented<'a, D> { 70 | inner: &'a mut D, 71 | number: Option, 72 | started: bool, 73 | } 74 | 75 | impl Write for Indented<'_, T> 76 | where 77 | T: Write, 78 | { 79 | fn write_str(&mut self, s: &str) -> fmt::Result { 80 | for (i, line) in s.split('\n').enumerate() { 81 | if !self.started { 82 | self.started = true; 83 | match self.number { 84 | Some(number) => write!(self.inner, "{: >5}: ", number)?, 85 | None => self.inner.write_str(" ")?, 86 | } 87 | } else if i > 0 { 88 | self.inner.write_char('\n')?; 89 | if self.number.is_some() { 90 | self.inner.write_str(" ")?; 91 | } else { 92 | self.inner.write_str(" ")?; 93 | } 94 | } 95 | 96 | self.inner.write_str(line)?; 97 | } 98 | 99 | Ok(()) 100 | } 101 | } 102 | 103 | #[cfg(test)] 104 | mod tests { 105 | use super::*; 106 | use alloc::string::String; 107 | 108 | #[test] 109 | fn one_digit() { 110 | let input = "verify\nthis"; 111 | let expected = " 2: verify\n this"; 112 | let mut output = String::new(); 113 | 114 | Indented { 115 | inner: &mut output, 116 | number: Some(2), 117 | started: false, 118 | } 119 | .write_str(input) 120 | .unwrap(); 121 | 122 | assert_eq!(expected, output); 123 | } 124 | 125 | #[test] 126 | fn two_digits() { 127 | let input = "verify\nthis"; 128 | let expected = " 12: verify\n this"; 129 | let mut output = String::new(); 130 | 131 | Indented { 132 | inner: &mut output, 133 | number: Some(12), 134 | started: false, 135 | } 136 | .write_str(input) 137 | .unwrap(); 138 | 139 | assert_eq!(expected, output); 140 | } 141 | 142 | #[test] 143 | fn no_digits() { 144 | let input = "verify\nthis"; 145 | let expected = " verify\n this"; 146 | let mut output = String::new(); 147 | 148 | Indented { 149 | inner: &mut output, 150 | number: None, 151 | started: false, 152 | } 153 | .write_str(input) 154 | .unwrap(); 155 | 156 | assert_eq!(expected, output); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/kind.rs: -------------------------------------------------------------------------------- 1 | // Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`. 2 | // 3 | // When anyhow! is given a single expr argument to turn into anyhow::Error, we 4 | // want the resulting Error to pick up the input's implementation of source() 5 | // and backtrace() if it has a std::error::Error impl, otherwise require nothing 6 | // more than Display and Debug. 7 | // 8 | // Expressed in terms of specialization, we want something like: 9 | // 10 | // trait AnyhowNew { 11 | // fn new(self) -> Error; 12 | // } 13 | // 14 | // impl AnyhowNew for T 15 | // where 16 | // T: Display + Debug + Send + Sync + 'static, 17 | // { 18 | // default fn new(self) -> Error { 19 | // /* no std error impl */ 20 | // } 21 | // } 22 | // 23 | // impl AnyhowNew for T 24 | // where 25 | // T: std::error::Error + Send + Sync + 'static, 26 | // { 27 | // fn new(self) -> Error { 28 | // /* use std error's source() and backtrace() */ 29 | // } 30 | // } 31 | // 32 | // Since specialization is not stable yet, instead we rely on autoref behavior 33 | // of method resolution to perform tagged dispatch. Here we have two traits 34 | // AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is 35 | // implemented whether or not the caller's type has a std error impl, while 36 | // TraitKind is implemented only when a std error impl does exist. The ambiguity 37 | // is resolved by AdhocKind requiring an extra autoref so that it has lower 38 | // precedence. 39 | // 40 | // The anyhow! macro will set up the call in this form: 41 | // 42 | // #[allow(unused_imports)] 43 | // use $crate::__private::{AdhocKind, TraitKind}; 44 | // let error = $msg; 45 | // (&error).anyhow_kind().new(error) 46 | 47 | use crate::Error; 48 | use core::fmt::{Debug, Display}; 49 | 50 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 51 | use crate::StdError; 52 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 53 | use alloc::boxed::Box; 54 | 55 | pub struct Adhoc; 56 | 57 | #[doc(hidden)] 58 | pub trait AdhocKind: Sized { 59 | #[inline] 60 | fn anyhow_kind(&self) -> Adhoc { 61 | Adhoc 62 | } 63 | } 64 | 65 | impl AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} 66 | 67 | impl Adhoc { 68 | #[cold] 69 | pub fn new(self, message: M) -> Error 70 | where 71 | M: Display + Debug + Send + Sync + 'static, 72 | { 73 | Error::construct_from_adhoc(message, backtrace!()) 74 | } 75 | } 76 | 77 | pub struct Trait; 78 | 79 | #[doc(hidden)] 80 | pub trait TraitKind: Sized { 81 | #[inline] 82 | fn anyhow_kind(&self) -> Trait { 83 | Trait 84 | } 85 | } 86 | 87 | impl TraitKind for E where E: Into {} 88 | 89 | impl Trait { 90 | #[cold] 91 | pub fn new(self, error: E) -> Error 92 | where 93 | E: Into, 94 | { 95 | error.into() 96 | } 97 | } 98 | 99 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 100 | pub struct Boxed; 101 | 102 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 103 | #[doc(hidden)] 104 | pub trait BoxedKind: Sized { 105 | #[inline] 106 | fn anyhow_kind(&self) -> Boxed { 107 | Boxed 108 | } 109 | } 110 | 111 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 112 | impl BoxedKind for Box {} 113 | 114 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 115 | impl Boxed { 116 | #[cold] 117 | pub fn new(self, error: Box) -> Error { 118 | let backtrace = backtrace_if_absent!(&*error); 119 | Error::construct_from_boxed(error, backtrace) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [![github]](https://github.com/dtolnay/anyhow) [![crates-io]](https://crates.io/crates/anyhow) [![docs-rs]](https://docs.rs/anyhow) 2 | //! 3 | //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github 4 | //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust 5 | //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs 6 | //! 7 | //!
8 | //! 9 | //! This library provides [`anyhow::Error`][Error], a trait object based error 10 | //! type for easy idiomatic error handling in Rust applications. 11 | //! 12 | //!
13 | //! 14 | //! # Details 15 | //! 16 | //! - Use `Result`, or equivalently `anyhow::Result`, as 17 | //! the return type of any fallible function. 18 | //! 19 | //! Within the function, use `?` to easily propagate any error that implements 20 | //! the [`std::error::Error`] trait. 21 | //! 22 | //! ``` 23 | //! # pub trait Deserialize {} 24 | //! # 25 | //! # mod serde_json { 26 | //! # use super::Deserialize; 27 | //! # use std::io; 28 | //! # 29 | //! # pub fn from_str(json: &str) -> io::Result { 30 | //! # unimplemented!() 31 | //! # } 32 | //! # } 33 | //! # 34 | //! # struct ClusterMap; 35 | //! # 36 | //! # impl Deserialize for ClusterMap {} 37 | //! # 38 | //! use anyhow::Result; 39 | //! 40 | //! fn get_cluster_info() -> Result { 41 | //! let config = std::fs::read_to_string("cluster.json")?; 42 | //! let map: ClusterMap = serde_json::from_str(&config)?; 43 | //! Ok(map) 44 | //! } 45 | //! # 46 | //! # fn main() {} 47 | //! ``` 48 | //! 49 | //! - Attach context to help the person troubleshooting the error understand 50 | //! where things went wrong. A low-level error like "No such file or 51 | //! directory" can be annoying to debug without more context about what higher 52 | //! level step the application was in the middle of. 53 | //! 54 | //! ``` 55 | //! # struct It; 56 | //! # 57 | //! # impl It { 58 | //! # fn detach(&self) -> Result<()> { 59 | //! # unimplemented!() 60 | //! # } 61 | //! # } 62 | //! # 63 | //! use anyhow::{Context, Result}; 64 | //! 65 | //! fn main() -> Result<()> { 66 | //! # return Ok(()); 67 | //! # 68 | //! # const _: &str = stringify! { 69 | //! ... 70 | //! # }; 71 | //! # 72 | //! # let it = It; 73 | //! # let path = "./path/to/instrs.json"; 74 | //! # 75 | //! it.detach().context("Failed to detach the important thing")?; 76 | //! 77 | //! let content = std::fs::read(path) 78 | //! .with_context(|| format!("Failed to read instrs from {}", path))?; 79 | //! # 80 | //! # const _: &str = stringify! { 81 | //! ... 82 | //! # }; 83 | //! # 84 | //! # Ok(()) 85 | //! } 86 | //! ``` 87 | //! 88 | //! ```console 89 | //! Error: Failed to read instrs from ./path/to/instrs.json 90 | //! 91 | //! Caused by: 92 | //! No such file or directory (os error 2) 93 | //! ``` 94 | //! 95 | //! - Downcasting is supported and can be by value, by shared reference, or by 96 | //! mutable reference as needed. 97 | //! 98 | //! ``` 99 | //! # use anyhow::anyhow; 100 | //! # use std::fmt::{self, Display}; 101 | //! # use std::task::Poll; 102 | //! # 103 | //! # #[derive(Debug)] 104 | //! # enum DataStoreError { 105 | //! # Censored(()), 106 | //! # } 107 | //! # 108 | //! # impl Display for DataStoreError { 109 | //! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 110 | //! # unimplemented!() 111 | //! # } 112 | //! # } 113 | //! # 114 | //! # impl std::error::Error for DataStoreError {} 115 | //! # 116 | //! # const REDACTED_CONTENT: () = (); 117 | //! # 118 | //! # let error = anyhow!("..."); 119 | //! # let root_cause = &error; 120 | //! # 121 | //! # let ret = 122 | //! // If the error was caused by redaction, then return a 123 | //! // tombstone instead of the content. 124 | //! match root_cause.downcast_ref::() { 125 | //! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), 126 | //! None => Err(error), 127 | //! } 128 | //! # ; 129 | //! ``` 130 | //! 131 | //! - If using Rust ≥ 1.65, a backtrace is captured and printed with the 132 | //! error if the underlying error type does not already provide its own. In 133 | //! order to see backtraces, they must be enabled through the environment 134 | //! variables described in [`std::backtrace`]: 135 | //! 136 | //! - If you want panics and errors to both have backtraces, set 137 | //! `RUST_BACKTRACE=1`; 138 | //! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; 139 | //! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and 140 | //! `RUST_LIB_BACKTRACE=0`. 141 | //! 142 | //! [`std::backtrace`]: std::backtrace#environment-variables 143 | //! 144 | //! - Anyhow works with any error type that has an impl of `std::error::Error`, 145 | //! including ones defined in your crate. We do not bundle a `derive(Error)` 146 | //! macro but you can write the impls yourself or use a standalone macro like 147 | //! [thiserror]. 148 | //! 149 | //! [thiserror]: https://github.com/dtolnay/thiserror 150 | //! 151 | //! ``` 152 | //! use thiserror::Error; 153 | //! 154 | //! #[derive(Error, Debug)] 155 | //! pub enum FormatError { 156 | //! #[error("Invalid header (expected {expected:?}, got {found:?})")] 157 | //! InvalidHeader { 158 | //! expected: String, 159 | //! found: String, 160 | //! }, 161 | //! #[error("Missing attribute: {0}")] 162 | //! MissingAttribute(String), 163 | //! } 164 | //! ``` 165 | //! 166 | //! - One-off error messages can be constructed using the `anyhow!` macro, which 167 | //! supports string interpolation and produces an `anyhow::Error`. 168 | //! 169 | //! ``` 170 | //! # use anyhow::{anyhow, Result}; 171 | //! # 172 | //! # fn demo() -> Result<()> { 173 | //! # let missing = "..."; 174 | //! return Err(anyhow!("Missing attribute: {}", missing)); 175 | //! # Ok(()) 176 | //! # } 177 | //! ``` 178 | //! 179 | //! A `bail!` macro is provided as a shorthand for the same early return. 180 | //! 181 | //! ``` 182 | //! # use anyhow::{bail, Result}; 183 | //! # 184 | //! # fn demo() -> Result<()> { 185 | //! # let missing = "..."; 186 | //! bail!("Missing attribute: {}", missing); 187 | //! # Ok(()) 188 | //! # } 189 | //! ``` 190 | //! 191 | //!
192 | //! 193 | //! # No-std support 194 | //! 195 | //! In no_std mode, almost all of the same API is available and works the same 196 | //! way. To depend on Anyhow in no_std mode, disable our default enabled "std" 197 | //! feature in Cargo.toml. A global allocator is required. 198 | //! 199 | //! ```toml 200 | //! [dependencies] 201 | //! anyhow = { version = "1.0", default-features = false } 202 | //! ``` 203 | //! 204 | //! With versions of Rust older than 1.81, no_std mode may require an additional 205 | //! `.map_err(Error::msg)` when working with a non-Anyhow error type inside a 206 | //! function that returns Anyhow's error type, as the trait that `?`-based error 207 | //! conversions are defined by is only available in std in those old versions. 208 | 209 | #![doc(html_root_url = "https://docs.rs/anyhow/1.0.98")] 210 | #![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] 211 | #![no_std] 212 | #![deny(dead_code, unused_imports, unused_mut)] 213 | #![cfg_attr( 214 | not(anyhow_no_unsafe_op_in_unsafe_fn_lint), 215 | deny(unsafe_op_in_unsafe_fn) 216 | )] 217 | #![cfg_attr(anyhow_no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))] 218 | #![allow( 219 | clippy::doc_markdown, 220 | clippy::elidable_lifetime_names, 221 | clippy::enum_glob_use, 222 | clippy::explicit_auto_deref, 223 | clippy::extra_unused_type_parameters, 224 | clippy::incompatible_msrv, 225 | clippy::let_underscore_untyped, 226 | clippy::missing_errors_doc, 227 | clippy::missing_panics_doc, 228 | clippy::module_name_repetitions, 229 | clippy::must_use_candidate, 230 | clippy::needless_doctest_main, 231 | clippy::needless_lifetimes, 232 | clippy::new_ret_no_self, 233 | clippy::redundant_else, 234 | clippy::return_self_not_must_use, 235 | clippy::struct_field_names, 236 | clippy::unused_self, 237 | clippy::used_underscore_binding, 238 | clippy::wildcard_imports, 239 | clippy::wrong_self_convention 240 | )] 241 | 242 | #[cfg(all( 243 | anyhow_nightly_testing, 244 | feature = "std", 245 | not(error_generic_member_access) 246 | ))] 247 | compile_error!("Build script probe failed to compile."); 248 | 249 | extern crate alloc; 250 | 251 | #[cfg(feature = "std")] 252 | extern crate std; 253 | 254 | #[macro_use] 255 | mod backtrace; 256 | mod chain; 257 | mod context; 258 | mod ensure; 259 | mod error; 260 | mod fmt; 261 | mod kind; 262 | mod macros; 263 | #[cfg(error_generic_member_access)] 264 | mod nightly; 265 | mod ptr; 266 | mod wrapper; 267 | 268 | use crate::error::ErrorImpl; 269 | use crate::ptr::Own; 270 | use core::fmt::Display; 271 | 272 | #[cfg(all(not(feature = "std"), anyhow_no_core_error))] 273 | use core::fmt::Debug; 274 | 275 | #[cfg(feature = "std")] 276 | use std::error::Error as StdError; 277 | 278 | #[cfg(not(any(feature = "std", anyhow_no_core_error)))] 279 | use core::error::Error as StdError; 280 | 281 | #[cfg(all(not(feature = "std"), anyhow_no_core_error))] 282 | trait StdError: Debug + Display { 283 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 284 | None 285 | } 286 | } 287 | 288 | #[doc(no_inline)] 289 | pub use anyhow as format_err; 290 | 291 | /// The `Error` type, a wrapper around a dynamic error type. 292 | /// 293 | /// `Error` works a lot like `Box`, but with these 294 | /// differences: 295 | /// 296 | /// - `Error` requires that the error is `Send`, `Sync`, and `'static`. 297 | /// - `Error` guarantees that a backtrace is available, even if the underlying 298 | /// error type does not provide one. 299 | /// - `Error` is represented as a narrow pointer — exactly one word in 300 | /// size instead of two. 301 | /// 302 | ///
303 | /// 304 | /// # Display representations 305 | /// 306 | /// When you print an error object using "{}" or to_string(), only the outermost 307 | /// underlying error or context is printed, not any of the lower level causes. 308 | /// This is exactly as if you had called the Display impl of the error from 309 | /// which you constructed your anyhow::Error. 310 | /// 311 | /// ```console 312 | /// Failed to read instrs from ./path/to/instrs.json 313 | /// ``` 314 | /// 315 | /// To print causes as well using anyhow's default formatting of causes, use the 316 | /// alternate selector "{:#}". 317 | /// 318 | /// ```console 319 | /// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2) 320 | /// ``` 321 | /// 322 | /// The Debug format "{:?}" includes your backtrace if one was captured. Note 323 | /// that this is the representation you get by default if you return an error 324 | /// from `fn main` instead of printing it explicitly yourself. 325 | /// 326 | /// ```console 327 | /// Error: Failed to read instrs from ./path/to/instrs.json 328 | /// 329 | /// Caused by: 330 | /// No such file or directory (os error 2) 331 | /// ``` 332 | /// 333 | /// and if there is a backtrace available: 334 | /// 335 | /// ```console 336 | /// Error: Failed to read instrs from ./path/to/instrs.json 337 | /// 338 | /// Caused by: 339 | /// No such file or directory (os error 2) 340 | /// 341 | /// Stack backtrace: 342 | /// 0: ::ext_context 343 | /// at /git/anyhow/src/backtrace.rs:26 344 | /// 1: core::result::Result::map_err 345 | /// at /git/rustc/src/libcore/result.rs:596 346 | /// 2: anyhow::context:: for core::result::Result>::with_context 347 | /// at /git/anyhow/src/context.rs:58 348 | /// 3: testing::main 349 | /// at src/main.rs:5 350 | /// 4: std::rt::lang_start 351 | /// at /git/rustc/src/libstd/rt.rs:61 352 | /// 5: main 353 | /// 6: __libc_start_main 354 | /// 7: _start 355 | /// ``` 356 | /// 357 | /// To see a conventional struct-style Debug representation, use "{:#?}". 358 | /// 359 | /// ```console 360 | /// Error { 361 | /// context: "Failed to read instrs from ./path/to/instrs.json", 362 | /// source: Os { 363 | /// code: 2, 364 | /// kind: NotFound, 365 | /// message: "No such file or directory", 366 | /// }, 367 | /// } 368 | /// ``` 369 | /// 370 | /// If none of the built-in representations are appropriate and you would prefer 371 | /// to render the error and its cause chain yourself, it can be done something 372 | /// like this: 373 | /// 374 | /// ``` 375 | /// use anyhow::{Context, Result}; 376 | /// 377 | /// fn main() { 378 | /// if let Err(err) = try_main() { 379 | /// eprintln!("ERROR: {}", err); 380 | /// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause)); 381 | /// std::process::exit(1); 382 | /// } 383 | /// } 384 | /// 385 | /// fn try_main() -> Result<()> { 386 | /// # const IGNORE: &str = stringify! { 387 | /// ... 388 | /// # }; 389 | /// # Ok(()) 390 | /// } 391 | /// ``` 392 | #[repr(transparent)] 393 | pub struct Error { 394 | inner: Own, 395 | } 396 | 397 | /// Iterator of a chain of source errors. 398 | /// 399 | /// This type is the iterator returned by [`Error::chain`]. 400 | /// 401 | /// # Example 402 | /// 403 | /// ``` 404 | /// use anyhow::Error; 405 | /// use std::io; 406 | /// 407 | /// pub fn underlying_io_error_kind(error: &Error) -> Option { 408 | /// for cause in error.chain() { 409 | /// if let Some(io_error) = cause.downcast_ref::() { 410 | /// return Some(io_error.kind()); 411 | /// } 412 | /// } 413 | /// None 414 | /// } 415 | /// ``` 416 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 417 | #[derive(Clone)] 418 | pub struct Chain<'a> { 419 | state: crate::chain::ChainState<'a>, 420 | } 421 | 422 | /// `Result` 423 | /// 424 | /// This is a reasonable return type to use throughout your application but also 425 | /// for `fn main`; if you do, failures will be printed along with any 426 | /// [context][Context] and a backtrace if one was captured. 427 | /// 428 | /// `anyhow::Result` may be used with one *or* two type parameters. 429 | /// 430 | /// ```rust 431 | /// use anyhow::Result; 432 | /// 433 | /// # const IGNORE: &str = stringify! { 434 | /// fn demo1() -> Result {...} 435 | /// // ^ equivalent to std::result::Result 436 | /// 437 | /// fn demo2() -> Result {...} 438 | /// // ^ equivalent to std::result::Result 439 | /// # }; 440 | /// ``` 441 | /// 442 | /// # Example 443 | /// 444 | /// ``` 445 | /// # pub trait Deserialize {} 446 | /// # 447 | /// # mod serde_json { 448 | /// # use super::Deserialize; 449 | /// # use std::io; 450 | /// # 451 | /// # pub fn from_str(json: &str) -> io::Result { 452 | /// # unimplemented!() 453 | /// # } 454 | /// # } 455 | /// # 456 | /// # #[derive(Debug)] 457 | /// # struct ClusterMap; 458 | /// # 459 | /// # impl Deserialize for ClusterMap {} 460 | /// # 461 | /// use anyhow::Result; 462 | /// 463 | /// fn main() -> Result<()> { 464 | /// # return Ok(()); 465 | /// let config = std::fs::read_to_string("cluster.json")?; 466 | /// let map: ClusterMap = serde_json::from_str(&config)?; 467 | /// println!("cluster info: {:#?}", map); 468 | /// Ok(()) 469 | /// } 470 | /// ``` 471 | pub type Result = core::result::Result; 472 | 473 | /// Provides the `context` method for `Result`. 474 | /// 475 | /// This trait is sealed and cannot be implemented for types outside of 476 | /// `anyhow`. 477 | /// 478 | ///
479 | /// 480 | /// # Example 481 | /// 482 | /// ``` 483 | /// use anyhow::{Context, Result}; 484 | /// use std::fs; 485 | /// use std::path::PathBuf; 486 | /// 487 | /// pub struct ImportantThing { 488 | /// path: PathBuf, 489 | /// } 490 | /// 491 | /// impl ImportantThing { 492 | /// # const IGNORE: &'static str = stringify! { 493 | /// pub fn detach(&mut self) -> Result<()> {...} 494 | /// # }; 495 | /// # fn detach(&mut self) -> Result<()> { 496 | /// # unimplemented!() 497 | /// # } 498 | /// } 499 | /// 500 | /// pub fn do_it(mut it: ImportantThing) -> Result> { 501 | /// it.detach().context("Failed to detach the important thing")?; 502 | /// 503 | /// let path = &it.path; 504 | /// let content = fs::read(path) 505 | /// .with_context(|| format!("Failed to read instrs from {}", path.display()))?; 506 | /// 507 | /// Ok(content) 508 | /// } 509 | /// ``` 510 | /// 511 | /// When printed, the outermost context would be printed first and the lower 512 | /// level underlying causes would be enumerated below. 513 | /// 514 | /// ```console 515 | /// Error: Failed to read instrs from ./path/to/instrs.json 516 | /// 517 | /// Caused by: 518 | /// No such file or directory (os error 2) 519 | /// ``` 520 | /// 521 | /// Refer to the [Display representations] documentation for other forms in 522 | /// which this context chain can be rendered. 523 | /// 524 | /// [Display representations]: Error#display-representations 525 | /// 526 | ///
527 | /// 528 | /// # Effect on downcasting 529 | /// 530 | /// After attaching context of type `C` onto an error of type `E`, the resulting 531 | /// `anyhow::Error` may be downcast to `C` **or** to `E`. 532 | /// 533 | /// That is, in codebases that rely on downcasting, Anyhow's context supports 534 | /// both of the following use cases: 535 | /// 536 | /// - **Attaching context whose type is insignificant onto errors whose type 537 | /// is used in downcasts.** 538 | /// 539 | /// In other error libraries whose context is not designed this way, it can 540 | /// be risky to introduce context to existing code because new context might 541 | /// break existing working downcasts. In Anyhow, any downcast that worked 542 | /// before adding context will continue to work after you add a context, so 543 | /// you should freely add human-readable context to errors wherever it would 544 | /// be helpful. 545 | /// 546 | /// ``` 547 | /// # use anyhow::bail; 548 | /// # use thiserror::Error; 549 | /// # 550 | /// # #[derive(Error, Debug)] 551 | /// # #[error("???")] 552 | /// # struct SuspiciousError; 553 | /// # 554 | /// # fn helper() -> Result<()> { 555 | /// # bail!(SuspiciousError); 556 | /// # } 557 | /// # 558 | /// use anyhow::{Context, Result}; 559 | /// 560 | /// fn do_it() -> Result<()> { 561 | /// helper().context("Failed to complete the work")?; 562 | /// # const IGNORE: &str = stringify! { 563 | /// ... 564 | /// # }; 565 | /// # unreachable!() 566 | /// } 567 | /// 568 | /// fn main() { 569 | /// let err = do_it().unwrap_err(); 570 | /// if let Some(e) = err.downcast_ref::() { 571 | /// // If helper() returned SuspiciousError, this downcast will 572 | /// // correctly succeed even with the context in between. 573 | /// # return; 574 | /// } 575 | /// # panic!("expected downcast to succeed"); 576 | /// } 577 | /// ``` 578 | /// 579 | /// - **Attaching context whose type is used in downcasts onto errors whose 580 | /// type is insignificant.** 581 | /// 582 | /// Some codebases prefer to use machine-readable context to categorize 583 | /// lower level errors in a way that will be actionable to higher levels of 584 | /// the application. 585 | /// 586 | /// ``` 587 | /// # use anyhow::bail; 588 | /// # use thiserror::Error; 589 | /// # 590 | /// # #[derive(Error, Debug)] 591 | /// # #[error("???")] 592 | /// # struct HelperFailed; 593 | /// # 594 | /// # fn helper() -> Result<()> { 595 | /// # bail!("no such file or directory"); 596 | /// # } 597 | /// # 598 | /// use anyhow::{Context, Result}; 599 | /// 600 | /// fn do_it() -> Result<()> { 601 | /// helper().context(HelperFailed)?; 602 | /// # const IGNORE: &str = stringify! { 603 | /// ... 604 | /// # }; 605 | /// # unreachable!() 606 | /// } 607 | /// 608 | /// fn main() { 609 | /// let err = do_it().unwrap_err(); 610 | /// if let Some(e) = err.downcast_ref::() { 611 | /// // If helper failed, this downcast will succeed because 612 | /// // HelperFailed is the context that has been attached to 613 | /// // that error. 614 | /// # return; 615 | /// } 616 | /// # panic!("expected downcast to succeed"); 617 | /// } 618 | /// ``` 619 | pub trait Context: context::private::Sealed { 620 | /// Wrap the error value with additional context. 621 | fn context(self, context: C) -> Result 622 | where 623 | C: Display + Send + Sync + 'static; 624 | 625 | /// Wrap the error value with additional context that is evaluated lazily 626 | /// only once an error does occur. 627 | fn with_context(self, f: F) -> Result 628 | where 629 | C: Display + Send + Sync + 'static, 630 | F: FnOnce() -> C; 631 | } 632 | 633 | /// Equivalent to `Ok::<_, anyhow::Error>(value)`. 634 | /// 635 | /// This simplifies creation of an `anyhow::Result` in places where type 636 | /// inference cannot deduce the `E` type of the result — without needing 637 | /// to write`Ok::<_, anyhow::Error>(value)`. 638 | /// 639 | /// One might think that `anyhow::Result::Ok(value)` would work in such cases 640 | /// but it does not. 641 | /// 642 | /// ```console 643 | /// error[E0282]: type annotations needed for `std::result::Result` 644 | /// --> src/main.rs:11:13 645 | /// | 646 | /// 11 | let _ = anyhow::Result::Ok(1); 647 | /// | - ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result` 648 | /// | | 649 | /// | consider giving this pattern the explicit type `std::result::Result`, where the type parameter `E` is specified 650 | /// ``` 651 | #[allow(non_snake_case)] 652 | pub fn Ok(value: T) -> Result { 653 | Result::Ok(value) 654 | } 655 | 656 | // Not public API. Referenced by macro-generated code. 657 | #[doc(hidden)] 658 | pub mod __private { 659 | use self::not::Bool; 660 | use crate::Error; 661 | use alloc::fmt; 662 | use core::fmt::Arguments; 663 | 664 | #[doc(hidden)] 665 | pub use crate::ensure::{BothDebug, NotBothDebug}; 666 | #[doc(hidden)] 667 | pub use alloc::format; 668 | #[doc(hidden)] 669 | pub use core::result::Result::Err; 670 | #[doc(hidden)] 671 | pub use core::{concat, format_args, stringify}; 672 | 673 | #[doc(hidden)] 674 | pub mod kind { 675 | #[doc(hidden)] 676 | pub use crate::kind::{AdhocKind, TraitKind}; 677 | 678 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 679 | #[doc(hidden)] 680 | pub use crate::kind::BoxedKind; 681 | } 682 | 683 | #[doc(hidden)] 684 | #[inline] 685 | #[cold] 686 | pub fn format_err(args: Arguments) -> Error { 687 | #[cfg(anyhow_no_fmt_arguments_as_str)] 688 | let fmt_arguments_as_str = None::<&str>; 689 | #[cfg(not(anyhow_no_fmt_arguments_as_str))] 690 | let fmt_arguments_as_str = args.as_str(); 691 | 692 | if let Some(message) = fmt_arguments_as_str { 693 | // anyhow!("literal"), can downcast to &'static str 694 | Error::msg(message) 695 | } else { 696 | // anyhow!("interpolate {var}"), can downcast to String 697 | Error::msg(fmt::format(args)) 698 | } 699 | } 700 | 701 | #[doc(hidden)] 702 | #[inline] 703 | #[cold] 704 | #[must_use] 705 | pub fn must_use(error: Error) -> Error { 706 | error 707 | } 708 | 709 | #[doc(hidden)] 710 | #[inline] 711 | pub fn not(cond: impl Bool) -> bool { 712 | cond.not() 713 | } 714 | 715 | mod not { 716 | #[doc(hidden)] 717 | pub trait Bool { 718 | fn not(self) -> bool; 719 | } 720 | 721 | impl Bool for bool { 722 | #[inline] 723 | fn not(self) -> bool { 724 | !self 725 | } 726 | } 727 | 728 | impl Bool for &bool { 729 | #[inline] 730 | fn not(self) -> bool { 731 | !*self 732 | } 733 | } 734 | } 735 | } 736 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Return early with an error. 2 | /// 3 | /// This macro is equivalent to 4 | /// return Err([anyhow!($args\...)][anyhow!]). 5 | /// 6 | /// The surrounding function's or closure's return value is required to be 7 | /// Result<_, [anyhow::Error][crate::Error]>. 8 | /// 9 | /// [anyhow!]: crate::anyhow 10 | /// 11 | /// # Example 12 | /// 13 | /// ``` 14 | /// # use anyhow::{bail, Result}; 15 | /// # 16 | /// # fn has_permission(user: usize, resource: usize) -> bool { 17 | /// # true 18 | /// # } 19 | /// # 20 | /// # fn main() -> Result<()> { 21 | /// # let user = 0; 22 | /// # let resource = 0; 23 | /// # 24 | /// if !has_permission(user, resource) { 25 | /// bail!("permission denied for accessing {}", resource); 26 | /// } 27 | /// # Ok(()) 28 | /// # } 29 | /// ``` 30 | /// 31 | /// ``` 32 | /// # use anyhow::{bail, Result}; 33 | /// # use thiserror::Error; 34 | /// # 35 | /// # const MAX_DEPTH: usize = 1; 36 | /// # 37 | /// #[derive(Error, Debug)] 38 | /// enum ScienceError { 39 | /// #[error("recursion limit exceeded")] 40 | /// RecursionLimitExceeded, 41 | /// # #[error("...")] 42 | /// # More = (stringify! { 43 | /// ... 44 | /// # }, 1).1, 45 | /// } 46 | /// 47 | /// # fn main() -> Result<()> { 48 | /// # let depth = 0; 49 | /// # 50 | /// if depth > MAX_DEPTH { 51 | /// bail!(ScienceError::RecursionLimitExceeded); 52 | /// } 53 | /// # Ok(()) 54 | /// # } 55 | /// ``` 56 | #[macro_export] 57 | macro_rules! bail { 58 | ($msg:literal $(,)?) => { 59 | return $crate::__private::Err($crate::__anyhow!($msg)) 60 | }; 61 | ($err:expr $(,)?) => { 62 | return $crate::__private::Err($crate::__anyhow!($err)) 63 | }; 64 | ($fmt:expr, $($arg:tt)*) => { 65 | return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)) 66 | }; 67 | } 68 | 69 | macro_rules! __ensure { 70 | ($ensure:item) => { 71 | /// Return early with an error if a condition is not satisfied. 72 | /// 73 | /// This macro is equivalent to 74 | /// if !$cond { return Err([anyhow!($args\...)][anyhow!]); }. 75 | /// 76 | /// The surrounding function's or closure's return value is required to be 77 | /// Result<_, [anyhow::Error][crate::Error]>. 78 | /// 79 | /// Analogously to `assert!`, `ensure!` takes a condition and exits the function 80 | /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` 81 | /// rather than panicking. 82 | /// 83 | /// [anyhow!]: crate::anyhow 84 | /// 85 | /// # Example 86 | /// 87 | /// ``` 88 | /// # use anyhow::{ensure, Result}; 89 | /// # 90 | /// # fn main() -> Result<()> { 91 | /// # let user = 0; 92 | /// # 93 | /// ensure!(user == 0, "only user 0 is allowed"); 94 | /// # Ok(()) 95 | /// # } 96 | /// ``` 97 | /// 98 | /// ``` 99 | /// # use anyhow::{ensure, Result}; 100 | /// # use thiserror::Error; 101 | /// # 102 | /// # const MAX_DEPTH: usize = 1; 103 | /// # 104 | /// #[derive(Error, Debug)] 105 | /// enum ScienceError { 106 | /// #[error("recursion limit exceeded")] 107 | /// RecursionLimitExceeded, 108 | /// # #[error("...")] 109 | /// # More = (stringify! { 110 | /// ... 111 | /// # }, 1).1, 112 | /// } 113 | /// 114 | /// # fn main() -> Result<()> { 115 | /// # let depth = 0; 116 | /// # 117 | /// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); 118 | /// # Ok(()) 119 | /// # } 120 | /// ``` 121 | $ensure 122 | }; 123 | } 124 | 125 | #[cfg(doc)] 126 | __ensure![ 127 | #[macro_export] 128 | macro_rules! ensure { 129 | ($cond:expr $(,)?) => { 130 | if !$cond { 131 | return $crate::__private::Err($crate::Error::msg( 132 | $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") 133 | )); 134 | } 135 | }; 136 | ($cond:expr, $msg:literal $(,)?) => { 137 | if !$cond { 138 | return $crate::__private::Err($crate::__anyhow!($msg)); 139 | } 140 | }; 141 | ($cond:expr, $err:expr $(,)?) => { 142 | if !$cond { 143 | return $crate::__private::Err($crate::__anyhow!($err)); 144 | } 145 | }; 146 | ($cond:expr, $fmt:expr, $($arg:tt)*) => { 147 | if !$cond { 148 | return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); 149 | } 150 | }; 151 | } 152 | ]; 153 | 154 | #[cfg(not(doc))] 155 | __ensure![ 156 | #[macro_export] 157 | macro_rules! ensure { 158 | ($($tt:tt)*) => { 159 | $crate::__parse_ensure!( 160 | /* state */ 0 161 | /* stack */ () 162 | /* bail */ ($($tt)*) 163 | /* fuel */ (~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~) 164 | /* parse */ {()} 165 | /* dup */ ($($tt)*) 166 | /* rest */ $($tt)* 167 | ) 168 | }; 169 | } 170 | ]; 171 | 172 | /// Construct an ad-hoc error from a string or existing non-`anyhow` error 173 | /// value. 174 | /// 175 | /// This evaluates to an [`Error`][crate::Error]. It can take either just a 176 | /// string, or a format string with arguments. It also can take any custom type 177 | /// which implements `Debug` and `Display`. 178 | /// 179 | /// If called with a single argument whose type implements `std::error::Error` 180 | /// (in addition to `Debug` and `Display`, which are always required), then that 181 | /// Error impl's `source` is preserved as the `source` of the resulting 182 | /// `anyhow::Error`. 183 | /// 184 | /// # Example 185 | /// 186 | /// ``` 187 | /// # type V = (); 188 | /// # 189 | /// use anyhow::{anyhow, Result}; 190 | /// 191 | /// fn lookup(key: &str) -> Result { 192 | /// if key.len() != 16 { 193 | /// return Err(anyhow!("key length must be 16 characters, got {:?}", key)); 194 | /// } 195 | /// 196 | /// // ... 197 | /// # Ok(()) 198 | /// } 199 | /// ``` 200 | #[macro_export] 201 | macro_rules! anyhow { 202 | ($msg:literal $(,)?) => { 203 | $crate::__private::must_use({ 204 | let error = $crate::__private::format_err($crate::__private::format_args!($msg)); 205 | error 206 | }) 207 | }; 208 | ($err:expr $(,)?) => { 209 | $crate::__private::must_use({ 210 | use $crate::__private::kind::*; 211 | let error = match $err { 212 | error => (&error).anyhow_kind().new(error), 213 | }; 214 | error 215 | }) 216 | }; 217 | ($fmt:expr, $($arg:tt)*) => { 218 | $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) 219 | }; 220 | } 221 | 222 | // Not public API. This is used in the implementation of some of the other 223 | // macros, in which the must_use call is not needed because the value is known 224 | // to be used. 225 | #[doc(hidden)] 226 | #[macro_export] 227 | macro_rules! __anyhow { 228 | ($msg:literal $(,)?) => ({ 229 | let error = $crate::__private::format_err($crate::__private::format_args!($msg)); 230 | error 231 | }); 232 | ($err:expr $(,)?) => ({ 233 | use $crate::__private::kind::*; 234 | let error = match $err { 235 | error => (&error).anyhow_kind().new(error), 236 | }; 237 | error 238 | }); 239 | ($fmt:expr, $($arg:tt)*) => { 240 | $crate::Error::msg($crate::__private::format!($fmt, $($arg)*)) 241 | }; 242 | } 243 | -------------------------------------------------------------------------------- /src/nightly.rs: -------------------------------------------------------------------------------- 1 | // This code exercises the surface area that we expect of the Error generic 2 | // member access API. If the current toolchain is able to compile it, then 3 | // anyhow is able to provide backtrace support. 4 | 5 | #![cfg_attr(anyhow_build_probe, feature(error_generic_member_access))] 6 | 7 | use core::error::{self, Error}; 8 | use std::backtrace::Backtrace; 9 | 10 | pub use core::error::Request; 11 | 12 | #[cfg(anyhow_build_probe)] 13 | const _: () = { 14 | use core::fmt::{self, Debug, Display}; 15 | 16 | struct MyError(Backtrace); 17 | 18 | impl Debug for MyError { 19 | fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { 20 | unimplemented!() 21 | } 22 | } 23 | 24 | impl Display for MyError { 25 | fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { 26 | unimplemented!() 27 | } 28 | } 29 | 30 | impl Error for MyError { 31 | fn provide<'a>(&'a self, request: &mut Request<'a>) { 32 | provide_ref_backtrace(request, &self.0); 33 | } 34 | } 35 | }; 36 | 37 | // Include in sccache cache key. 38 | #[cfg(anyhow_build_probe)] 39 | const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP"); 40 | 41 | pub fn request_ref_backtrace(err: &dyn Error) -> Option<&Backtrace> { 42 | request_ref::(err) 43 | } 44 | 45 | fn request_ref<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<&'a T> 46 | where 47 | T: 'static + ?Sized, 48 | { 49 | error::request_ref::(err) 50 | } 51 | 52 | pub fn provide_ref_backtrace<'a>(request: &mut Request<'a>, backtrace: &'a Backtrace) { 53 | Request::provide_ref(request, backtrace); 54 | } 55 | 56 | pub fn provide<'a>(err: &'a (impl Error + ?Sized), request: &mut Request<'a>) { 57 | Error::provide(err, request); 58 | } 59 | -------------------------------------------------------------------------------- /src/ptr.rs: -------------------------------------------------------------------------------- 1 | use alloc::boxed::Box; 2 | use core::marker::PhantomData; 3 | use core::ptr::NonNull; 4 | 5 | #[repr(transparent)] 6 | pub struct Own 7 | where 8 | T: ?Sized, 9 | { 10 | pub ptr: NonNull, 11 | } 12 | 13 | unsafe impl Send for Own where T: ?Sized {} 14 | 15 | unsafe impl Sync for Own where T: ?Sized {} 16 | 17 | impl Copy for Own where T: ?Sized {} 18 | 19 | impl Clone for Own 20 | where 21 | T: ?Sized, 22 | { 23 | fn clone(&self) -> Self { 24 | *self 25 | } 26 | } 27 | 28 | impl Own 29 | where 30 | T: ?Sized, 31 | { 32 | pub fn new(ptr: Box) -> Self { 33 | Own { 34 | ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) }, 35 | } 36 | } 37 | 38 | pub fn cast(self) -> Own { 39 | Own { 40 | ptr: self.ptr.cast(), 41 | } 42 | } 43 | 44 | pub unsafe fn boxed(self) -> Box { 45 | unsafe { Box::from_raw(self.ptr.as_ptr()) } 46 | } 47 | 48 | pub fn by_ref(&self) -> Ref { 49 | Ref { 50 | ptr: self.ptr, 51 | lifetime: PhantomData, 52 | } 53 | } 54 | 55 | pub fn by_mut(&mut self) -> Mut { 56 | Mut { 57 | ptr: self.ptr, 58 | lifetime: PhantomData, 59 | } 60 | } 61 | } 62 | 63 | #[repr(transparent)] 64 | pub struct Ref<'a, T> 65 | where 66 | T: ?Sized, 67 | { 68 | pub ptr: NonNull, 69 | lifetime: PhantomData<&'a T>, 70 | } 71 | 72 | impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {} 73 | 74 | impl<'a, T> Clone for Ref<'a, T> 75 | where 76 | T: ?Sized, 77 | { 78 | fn clone(&self) -> Self { 79 | *self 80 | } 81 | } 82 | 83 | impl<'a, T> Ref<'a, T> 84 | where 85 | T: ?Sized, 86 | { 87 | pub fn new(ptr: &'a T) -> Self { 88 | Ref { 89 | ptr: NonNull::from(ptr), 90 | lifetime: PhantomData, 91 | } 92 | } 93 | 94 | #[cfg(not(anyhow_no_ptr_addr_of))] 95 | pub fn from_raw(ptr: NonNull) -> Self { 96 | Ref { 97 | ptr, 98 | lifetime: PhantomData, 99 | } 100 | } 101 | 102 | pub fn cast(self) -> Ref<'a, U::Target> { 103 | Ref { 104 | ptr: self.ptr.cast(), 105 | lifetime: PhantomData, 106 | } 107 | } 108 | 109 | #[cfg(not(anyhow_no_ptr_addr_of))] 110 | pub fn by_mut(self) -> Mut<'a, T> { 111 | Mut { 112 | ptr: self.ptr, 113 | lifetime: PhantomData, 114 | } 115 | } 116 | 117 | #[cfg(not(anyhow_no_ptr_addr_of))] 118 | pub fn as_ptr(self) -> *const T { 119 | self.ptr.as_ptr() as *const T 120 | } 121 | 122 | pub unsafe fn deref(self) -> &'a T { 123 | unsafe { &*self.ptr.as_ptr() } 124 | } 125 | } 126 | 127 | #[repr(transparent)] 128 | pub struct Mut<'a, T> 129 | where 130 | T: ?Sized, 131 | { 132 | pub ptr: NonNull, 133 | lifetime: PhantomData<&'a mut T>, 134 | } 135 | 136 | impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {} 137 | 138 | impl<'a, T> Clone for Mut<'a, T> 139 | where 140 | T: ?Sized, 141 | { 142 | fn clone(&self) -> Self { 143 | *self 144 | } 145 | } 146 | 147 | impl<'a, T> Mut<'a, T> 148 | where 149 | T: ?Sized, 150 | { 151 | #[cfg(anyhow_no_ptr_addr_of)] 152 | pub fn new(ptr: &'a mut T) -> Self { 153 | Mut { 154 | ptr: NonNull::from(ptr), 155 | lifetime: PhantomData, 156 | } 157 | } 158 | 159 | pub fn cast(self) -> Mut<'a, U::Target> { 160 | Mut { 161 | ptr: self.ptr.cast(), 162 | lifetime: PhantomData, 163 | } 164 | } 165 | 166 | #[cfg(not(anyhow_no_ptr_addr_of))] 167 | pub fn by_ref(self) -> Ref<'a, T> { 168 | Ref { 169 | ptr: self.ptr, 170 | lifetime: PhantomData, 171 | } 172 | } 173 | 174 | pub fn extend<'b>(self) -> Mut<'b, T> { 175 | Mut { 176 | ptr: self.ptr, 177 | lifetime: PhantomData, 178 | } 179 | } 180 | 181 | pub unsafe fn deref_mut(self) -> &'a mut T { 182 | unsafe { &mut *self.ptr.as_ptr() } 183 | } 184 | } 185 | 186 | impl<'a, T> Mut<'a, T> { 187 | pub unsafe fn read(self) -> T { 188 | unsafe { self.ptr.as_ptr().read() } 189 | } 190 | } 191 | 192 | // Force turbofish on all calls of `.cast::()`. 193 | pub trait CastTo { 194 | type Target; 195 | } 196 | 197 | impl CastTo for T { 198 | type Target = T; 199 | } 200 | -------------------------------------------------------------------------------- /src/wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::StdError; 2 | use core::fmt::{self, Debug, Display}; 3 | 4 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 5 | use alloc::boxed::Box; 6 | 7 | #[cfg(error_generic_member_access)] 8 | use crate::nightly::{self, Request}; 9 | 10 | #[repr(transparent)] 11 | pub struct MessageError(pub M); 12 | 13 | impl Debug for MessageError 14 | where 15 | M: Display + Debug, 16 | { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | Debug::fmt(&self.0, f) 19 | } 20 | } 21 | 22 | impl Display for MessageError 23 | where 24 | M: Display + Debug, 25 | { 26 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 27 | Display::fmt(&self.0, f) 28 | } 29 | } 30 | 31 | impl StdError for MessageError where M: Display + Debug + 'static {} 32 | 33 | #[repr(transparent)] 34 | pub struct DisplayError(pub M); 35 | 36 | impl Debug for DisplayError 37 | where 38 | M: Display, 39 | { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | Display::fmt(&self.0, f) 42 | } 43 | } 44 | 45 | impl Display for DisplayError 46 | where 47 | M: Display, 48 | { 49 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | Display::fmt(&self.0, f) 51 | } 52 | } 53 | 54 | impl StdError for DisplayError where M: Display + 'static {} 55 | 56 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 57 | #[repr(transparent)] 58 | pub struct BoxedError(pub Box); 59 | 60 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 61 | impl Debug for BoxedError { 62 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 63 | Debug::fmt(&self.0, f) 64 | } 65 | } 66 | 67 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 68 | impl Display for BoxedError { 69 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 70 | Display::fmt(&self.0, f) 71 | } 72 | } 73 | 74 | #[cfg(any(feature = "std", not(anyhow_no_core_error)))] 75 | impl StdError for BoxedError { 76 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 77 | self.0.source() 78 | } 79 | 80 | #[cfg(error_generic_member_access)] 81 | fn provide<'a>(&'a self, request: &mut Request<'a>) { 82 | nightly::provide(&*self.0, request); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Result}; 2 | use std::io; 3 | 4 | pub fn bail_literal() -> Result<()> { 5 | bail!("oh no!"); 6 | } 7 | 8 | pub fn bail_fmt() -> Result<()> { 9 | bail!("{} {}!", "oh", "no"); 10 | } 11 | 12 | pub fn bail_error() -> Result<()> { 13 | bail!(io::Error::new(io::ErrorKind::Other, "oh no!")); 14 | } 15 | -------------------------------------------------------------------------------- /tests/compiletest.rs: -------------------------------------------------------------------------------- 1 | #[rustversion::attr(not(nightly), ignore = "requires nightly")] 2 | #[cfg_attr(miri, ignore = "incompatible with miri")] 3 | #[test] 4 | fn ui() { 5 | let t = trybuild::TestCases::new(); 6 | t.compile_fail("tests/ui/*.rs"); 7 | } 8 | -------------------------------------------------------------------------------- /tests/crate/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /tests/crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "anyhow_test" 3 | version = "0.0.0" 4 | authors = ["David Tolnay "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [lib] 9 | path = "test.rs" 10 | 11 | [dependencies] 12 | anyhow = { path = "../..", default-features = false } 13 | 14 | [features] 15 | default = ["std"] 16 | std = ["anyhow/std"] 17 | backtrace = ["anyhow/backtrace"] 18 | -------------------------------------------------------------------------------- /tests/crate/test.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub use anyhow::*; 4 | -------------------------------------------------------------------------------- /tests/drop/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::module_name_repetitions)] 2 | 3 | use std::error::Error as StdError; 4 | use std::fmt::{self, Display}; 5 | use std::sync::atomic::{AtomicBool, Ordering}; 6 | use std::sync::Arc; 7 | 8 | #[derive(Debug)] 9 | pub struct Flag { 10 | atomic: Arc, 11 | } 12 | 13 | impl Flag { 14 | pub fn new() -> Self { 15 | Flag { 16 | atomic: Arc::new(AtomicBool::new(false)), 17 | } 18 | } 19 | 20 | pub fn get(&self) -> bool { 21 | self.atomic.load(Ordering::Relaxed) 22 | } 23 | } 24 | 25 | #[derive(Debug)] 26 | pub struct DetectDrop { 27 | has_dropped: Flag, 28 | } 29 | 30 | impl DetectDrop { 31 | pub fn new(has_dropped: &Flag) -> Self { 32 | DetectDrop { 33 | has_dropped: Flag { 34 | atomic: Arc::clone(&has_dropped.atomic), 35 | }, 36 | } 37 | } 38 | } 39 | 40 | impl StdError for DetectDrop {} 41 | 42 | impl Display for DetectDrop { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | write!(f, "oh no!") 45 | } 46 | } 47 | 48 | impl Drop for DetectDrop { 49 | fn drop(&mut self) { 50 | let already_dropped = self.has_dropped.atomic.swap(true, Ordering::Relaxed); 51 | assert!(!already_dropped); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/test_autotrait.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::extra_unused_type_parameters)] 2 | 3 | use anyhow::Error; 4 | use std::panic::{RefUnwindSafe, UnwindSafe}; 5 | 6 | #[test] 7 | fn test_send() { 8 | fn assert_send() {} 9 | assert_send::(); 10 | } 11 | 12 | #[test] 13 | fn test_sync() { 14 | fn assert_sync() {} 15 | assert_sync::(); 16 | } 17 | 18 | #[test] 19 | fn test_unwind_safe() { 20 | fn assert_unwind_safe() {} 21 | assert_unwind_safe::(); 22 | } 23 | 24 | #[test] 25 | fn test_ref_unwind_safe() { 26 | fn assert_ref_unwind_safe() {} 27 | assert_ref_unwind_safe::(); 28 | } 29 | 30 | #[test] 31 | fn test_unpin() { 32 | fn assert_unpin() {} 33 | assert_unpin::(); 34 | } 35 | -------------------------------------------------------------------------------- /tests/test_backtrace.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::let_underscore_untyped)] 2 | 3 | #[rustversion::not(nightly)] 4 | #[ignore = "requires nightly"] 5 | #[test] 6 | fn test_backtrace() {} 7 | 8 | #[rustversion::nightly] 9 | #[test] 10 | fn test_backtrace() { 11 | use anyhow::anyhow; 12 | 13 | let error = anyhow!("oh no!"); 14 | let _ = error.backtrace(); 15 | } 16 | -------------------------------------------------------------------------------- /tests/test_boxed.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 3 | clippy::nonstandard_macro_braces, 4 | )] 5 | 6 | use anyhow::anyhow; 7 | use std::error::Error as StdError; 8 | use std::io; 9 | use thiserror::Error; 10 | 11 | #[derive(Error, Debug)] 12 | #[error("outer")] 13 | struct MyError { 14 | source: io::Error, 15 | } 16 | 17 | #[test] 18 | fn test_boxed_str() { 19 | let error = Box::::from("oh no!"); 20 | let error = anyhow!(error); 21 | assert_eq!("oh no!", error.to_string()); 22 | assert_eq!( 23 | "oh no!", 24 | error 25 | .downcast_ref::>() 26 | .unwrap() 27 | .to_string() 28 | ); 29 | } 30 | 31 | #[test] 32 | fn test_boxed_thiserror() { 33 | let error = MyError { 34 | source: io::Error::new(io::ErrorKind::Other, "oh no!"), 35 | }; 36 | let error = anyhow!(error); 37 | assert_eq!("oh no!", error.source().unwrap().to_string()); 38 | } 39 | 40 | #[test] 41 | fn test_boxed_anyhow() { 42 | let error = anyhow!("oh no!").context("it failed"); 43 | let error = anyhow!(error); 44 | assert_eq!("oh no!", error.source().unwrap().to_string()); 45 | } 46 | -------------------------------------------------------------------------------- /tests/test_chain.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Chain, Error}; 2 | 3 | fn error() -> Error { 4 | anyhow!({ 0 }).context(1).context(2).context(3) 5 | } 6 | 7 | #[test] 8 | fn test_iter() { 9 | let e = error(); 10 | let mut chain = e.chain(); 11 | assert_eq!("3", chain.next().unwrap().to_string()); 12 | assert_eq!("2", chain.next().unwrap().to_string()); 13 | assert_eq!("1", chain.next().unwrap().to_string()); 14 | assert_eq!("0", chain.next().unwrap().to_string()); 15 | assert!(chain.next().is_none()); 16 | assert!(chain.next_back().is_none()); 17 | } 18 | 19 | #[test] 20 | fn test_rev() { 21 | let e = error(); 22 | let mut chain = e.chain().rev(); 23 | assert_eq!("0", chain.next().unwrap().to_string()); 24 | assert_eq!("1", chain.next().unwrap().to_string()); 25 | assert_eq!("2", chain.next().unwrap().to_string()); 26 | assert_eq!("3", chain.next().unwrap().to_string()); 27 | assert!(chain.next().is_none()); 28 | assert!(chain.next_back().is_none()); 29 | } 30 | 31 | #[test] 32 | fn test_len() { 33 | let e = error(); 34 | let mut chain = e.chain(); 35 | assert_eq!(4, chain.len()); 36 | assert_eq!((4, Some(4)), chain.size_hint()); 37 | assert_eq!("3", chain.next().unwrap().to_string()); 38 | assert_eq!(3, chain.len()); 39 | assert_eq!((3, Some(3)), chain.size_hint()); 40 | assert_eq!("0", chain.next_back().unwrap().to_string()); 41 | assert_eq!(2, chain.len()); 42 | assert_eq!((2, Some(2)), chain.size_hint()); 43 | assert_eq!("2", chain.next().unwrap().to_string()); 44 | assert_eq!(1, chain.len()); 45 | assert_eq!((1, Some(1)), chain.size_hint()); 46 | assert_eq!("1", chain.next_back().unwrap().to_string()); 47 | assert_eq!(0, chain.len()); 48 | assert_eq!((0, Some(0)), chain.size_hint()); 49 | assert!(chain.next().is_none()); 50 | } 51 | 52 | #[test] 53 | fn test_default() { 54 | let mut c = Chain::default(); 55 | assert!(c.next().is_none()); 56 | } 57 | 58 | #[test] 59 | #[allow(clippy::redundant_clone)] 60 | fn test_clone() { 61 | let e = error(); 62 | let mut chain = e.chain().clone(); 63 | assert_eq!("3", chain.next().unwrap().to_string()); 64 | assert_eq!("2", chain.next().unwrap().to_string()); 65 | assert_eq!("1", chain.next().unwrap().to_string()); 66 | assert_eq!("0", chain.next().unwrap().to_string()); 67 | assert!(chain.next().is_none()); 68 | assert!(chain.next_back().is_none()); 69 | } 70 | -------------------------------------------------------------------------------- /tests/test_context.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 3 | clippy::nonstandard_macro_braces, 4 | )] 5 | 6 | mod drop; 7 | 8 | use crate::drop::{DetectDrop, Flag}; 9 | use anyhow::{Context, Error, Result}; 10 | use std::fmt::{self, Display}; 11 | use thiserror::Error; 12 | 13 | // https://github.com/dtolnay/anyhow/issues/18 14 | #[test] 15 | fn test_inference() -> Result<()> { 16 | let x = "1"; 17 | let y: u32 = x.parse().context("...")?; 18 | assert_eq!(y, 1); 19 | Ok(()) 20 | } 21 | 22 | macro_rules! context_type { 23 | ($name:ident) => { 24 | #[derive(Debug)] 25 | struct $name { 26 | message: &'static str, 27 | #[allow(dead_code)] 28 | drop: DetectDrop, 29 | } 30 | 31 | impl Display for $name { 32 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 33 | f.write_str(self.message) 34 | } 35 | } 36 | }; 37 | } 38 | 39 | context_type!(HighLevel); 40 | context_type!(MidLevel); 41 | 42 | #[derive(Error, Debug)] 43 | #[error("{message}")] 44 | struct LowLevel { 45 | message: &'static str, 46 | drop: DetectDrop, 47 | } 48 | 49 | struct Dropped { 50 | low: Flag, 51 | mid: Flag, 52 | high: Flag, 53 | } 54 | 55 | impl Dropped { 56 | fn none(&self) -> bool { 57 | !self.low.get() && !self.mid.get() && !self.high.get() 58 | } 59 | 60 | fn all(&self) -> bool { 61 | self.low.get() && self.mid.get() && self.high.get() 62 | } 63 | } 64 | 65 | fn make_chain() -> (Error, Dropped) { 66 | let dropped = Dropped { 67 | low: Flag::new(), 68 | mid: Flag::new(), 69 | high: Flag::new(), 70 | }; 71 | 72 | let low = LowLevel { 73 | message: "no such file or directory", 74 | drop: DetectDrop::new(&dropped.low), 75 | }; 76 | 77 | // impl Context for Result 78 | let mid = Err::<(), LowLevel>(low) 79 | .context(MidLevel { 80 | message: "failed to load config", 81 | drop: DetectDrop::new(&dropped.mid), 82 | }) 83 | .unwrap_err(); 84 | 85 | // impl Context for Result 86 | let high = Err::<(), Error>(mid) 87 | .context(HighLevel { 88 | message: "failed to start server", 89 | drop: DetectDrop::new(&dropped.high), 90 | }) 91 | .unwrap_err(); 92 | 93 | (high, dropped) 94 | } 95 | 96 | #[test] 97 | fn test_downcast_ref() { 98 | let (err, dropped) = make_chain(); 99 | 100 | assert!(!err.is::()); 101 | assert!(err.downcast_ref::().is_none()); 102 | 103 | assert!(err.is::()); 104 | let high = err.downcast_ref::().unwrap(); 105 | assert_eq!(high.to_string(), "failed to start server"); 106 | 107 | assert!(err.is::()); 108 | let mid = err.downcast_ref::().unwrap(); 109 | assert_eq!(mid.to_string(), "failed to load config"); 110 | 111 | assert!(err.is::()); 112 | let low = err.downcast_ref::().unwrap(); 113 | assert_eq!(low.to_string(), "no such file or directory"); 114 | 115 | assert!(dropped.none()); 116 | drop(err); 117 | assert!(dropped.all()); 118 | } 119 | 120 | #[test] 121 | fn test_downcast_high() { 122 | let (err, dropped) = make_chain(); 123 | 124 | let err = err.downcast::().unwrap(); 125 | assert!(!dropped.high.get()); 126 | assert!(dropped.low.get() && dropped.mid.get()); 127 | 128 | drop(err); 129 | assert!(dropped.all()); 130 | } 131 | 132 | #[test] 133 | fn test_downcast_mid() { 134 | let (err, dropped) = make_chain(); 135 | 136 | let err = err.downcast::().unwrap(); 137 | assert!(!dropped.mid.get()); 138 | assert!(dropped.low.get() && dropped.high.get()); 139 | 140 | drop(err); 141 | assert!(dropped.all()); 142 | } 143 | 144 | #[test] 145 | fn test_downcast_low() { 146 | let (err, dropped) = make_chain(); 147 | 148 | let err = err.downcast::().unwrap(); 149 | assert!(!dropped.low.get()); 150 | assert!(dropped.mid.get() && dropped.high.get()); 151 | 152 | drop(err); 153 | assert!(dropped.all()); 154 | } 155 | 156 | #[test] 157 | fn test_unsuccessful_downcast() { 158 | let (err, dropped) = make_chain(); 159 | 160 | let err = err.downcast::().unwrap_err(); 161 | assert!(dropped.none()); 162 | 163 | drop(err); 164 | assert!(dropped.all()); 165 | } 166 | 167 | #[test] 168 | fn test_root_cause() { 169 | let (err, _) = make_chain(); 170 | 171 | assert_eq!(err.root_cause().to_string(), "no such file or directory"); 172 | } 173 | -------------------------------------------------------------------------------- /tests/test_convert.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unnecessary_wraps)] 2 | 3 | mod drop; 4 | 5 | use self::drop::{DetectDrop, Flag}; 6 | use anyhow::{Error, Result}; 7 | use std::error::Error as StdError; 8 | 9 | #[test] 10 | fn test_convert() { 11 | let has_dropped = Flag::new(); 12 | let error = Error::new(DetectDrop::new(&has_dropped)); 13 | let box_dyn = Box::::from(error); 14 | assert_eq!("oh no!", box_dyn.to_string()); 15 | drop(box_dyn); 16 | assert!(has_dropped.get()); 17 | } 18 | 19 | #[test] 20 | fn test_convert_send() { 21 | let has_dropped = Flag::new(); 22 | let error = Error::new(DetectDrop::new(&has_dropped)); 23 | let box_dyn = Box::::from(error); 24 | assert_eq!("oh no!", box_dyn.to_string()); 25 | drop(box_dyn); 26 | assert!(has_dropped.get()); 27 | } 28 | 29 | #[test] 30 | fn test_convert_send_sync() { 31 | let has_dropped = Flag::new(); 32 | let error = Error::new(DetectDrop::new(&has_dropped)); 33 | let box_dyn = Box::::from(error); 34 | assert_eq!("oh no!", box_dyn.to_string()); 35 | drop(box_dyn); 36 | assert!(has_dropped.get()); 37 | } 38 | 39 | #[test] 40 | fn test_question_mark() -> Result<(), Box> { 41 | fn f() -> Result<()> { 42 | Ok(()) 43 | } 44 | f()?; 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /tests/test_downcast.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::assertions_on_result_states, clippy::wildcard_imports)] 2 | 3 | mod common; 4 | mod drop; 5 | 6 | use self::common::*; 7 | use self::drop::{DetectDrop, Flag}; 8 | use anyhow::Error; 9 | use std::error::Error as StdError; 10 | use std::fmt::{self, Display}; 11 | use std::io; 12 | 13 | #[test] 14 | fn test_downcast() { 15 | assert_eq!( 16 | "oh no!", 17 | bail_literal().unwrap_err().downcast::<&str>().unwrap(), 18 | ); 19 | assert_eq!( 20 | "oh no!", 21 | bail_fmt().unwrap_err().downcast::().unwrap(), 22 | ); 23 | assert_eq!( 24 | "oh no!", 25 | bail_error() 26 | .unwrap_err() 27 | .downcast::() 28 | .unwrap() 29 | .to_string(), 30 | ); 31 | } 32 | 33 | #[test] 34 | fn test_downcast_ref() { 35 | assert_eq!( 36 | "oh no!", 37 | *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(), 38 | ); 39 | assert_eq!( 40 | "oh no!", 41 | bail_fmt().unwrap_err().downcast_ref::().unwrap(), 42 | ); 43 | assert_eq!( 44 | "oh no!", 45 | bail_error() 46 | .unwrap_err() 47 | .downcast_ref::() 48 | .unwrap() 49 | .to_string(), 50 | ); 51 | } 52 | 53 | #[test] 54 | fn test_downcast_mut() { 55 | assert_eq!( 56 | "oh no!", 57 | *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(), 58 | ); 59 | assert_eq!( 60 | "oh no!", 61 | bail_fmt().unwrap_err().downcast_mut::().unwrap(), 62 | ); 63 | assert_eq!( 64 | "oh no!", 65 | bail_error() 66 | .unwrap_err() 67 | .downcast_mut::() 68 | .unwrap() 69 | .to_string(), 70 | ); 71 | 72 | let mut bailed = bail_fmt().unwrap_err(); 73 | *bailed.downcast_mut::().unwrap() = "clobber".to_string(); 74 | assert_eq!(bailed.downcast_ref::().unwrap(), "clobber"); 75 | assert_eq!(bailed.downcast_mut::().unwrap(), "clobber"); 76 | assert_eq!(bailed.downcast::().unwrap(), "clobber"); 77 | } 78 | 79 | #[test] 80 | fn test_drop() { 81 | let has_dropped = Flag::new(); 82 | let error = Error::new(DetectDrop::new(&has_dropped)); 83 | drop(error.downcast::().unwrap()); 84 | assert!(has_dropped.get()); 85 | } 86 | 87 | #[test] 88 | fn test_as_ref() { 89 | let error = bail_error().unwrap_err(); 90 | let ref_dyn: &dyn StdError = error.as_ref(); 91 | assert_eq!("oh no!", ref_dyn.to_string()); 92 | let ref_dyn_send_sync: &(dyn StdError + Send + Sync) = error.as_ref(); 93 | assert_eq!("oh no!", ref_dyn_send_sync.to_string()); 94 | } 95 | 96 | #[test] 97 | fn test_large_alignment() { 98 | #[repr(align(64))] 99 | #[derive(Debug)] 100 | struct LargeAlignedError(&'static str); 101 | 102 | impl Display for LargeAlignedError { 103 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 104 | f.write_str(self.0) 105 | } 106 | } 107 | 108 | impl StdError for LargeAlignedError {} 109 | 110 | let error = Error::new(LargeAlignedError("oh no!")); 111 | assert_eq!( 112 | "oh no!", 113 | error.downcast_ref::().unwrap().0 114 | ); 115 | } 116 | 117 | #[test] 118 | fn test_unsuccessful_downcast() { 119 | let mut error = bail_error().unwrap_err(); 120 | assert!(error.downcast_ref::<&str>().is_none()); 121 | assert!(error.downcast_mut::<&str>().is_none()); 122 | assert!(error.downcast::<&str>().is_err()); 123 | } 124 | -------------------------------------------------------------------------------- /tests/test_ensure.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::bool_to_int_with_if, 3 | clippy::char_lit_as_u8, 4 | clippy::deref_addrof, 5 | clippy::diverging_sub_expression, 6 | clippy::erasing_op, 7 | clippy::extra_unused_type_parameters, 8 | clippy::if_same_then_else, 9 | clippy::ifs_same_cond, 10 | clippy::ignored_unit_patterns, 11 | clippy::items_after_statements, 12 | clippy::let_and_return, 13 | clippy::let_underscore_untyped, 14 | clippy::literal_string_with_formatting_args, 15 | clippy::match_bool, 16 | clippy::needless_else, 17 | clippy::never_loop, 18 | clippy::overly_complex_bool_expr, 19 | clippy::redundant_closure_call, 20 | clippy::redundant_pattern_matching, 21 | clippy::too_many_lines, 22 | clippy::unit_arg, 23 | clippy::unnecessary_cast, 24 | clippy::while_immutable_condition, 25 | clippy::zero_ptr, 26 | irrefutable_let_patterns 27 | )] 28 | 29 | use self::Enum::Generic; 30 | use anyhow::{anyhow, ensure, Chain, Error, Result}; 31 | use std::fmt::{self, Debug}; 32 | use std::iter; 33 | use std::marker::{PhantomData, PhantomData as P}; 34 | use std::mem; 35 | use std::ops::Add; 36 | use std::ptr; 37 | 38 | struct S; 39 | 40 | impl Add for S { 41 | type Output = bool; 42 | fn add(self, rhs: T) -> Self::Output { 43 | let _ = rhs; 44 | false 45 | } 46 | } 47 | 48 | trait Trait: Sized { 49 | const V: usize = 0; 50 | fn t(self, i: i32) -> i32 { 51 | i 52 | } 53 | } 54 | 55 | impl Trait for T {} 56 | 57 | enum Enum { 58 | #[allow(dead_code)] 59 | Thing(PhantomData), 60 | Generic, 61 | } 62 | 63 | impl PartialEq for Enum { 64 | fn eq(&self, rhs: &Self) -> bool { 65 | mem::discriminant(self) == mem::discriminant(rhs) 66 | } 67 | } 68 | 69 | impl Debug for Enum { 70 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 71 | formatter.write_str("Generic") 72 | } 73 | } 74 | 75 | #[track_caller] 76 | fn assert_err(result: impl FnOnce() -> Result, expected: &'static str) { 77 | let actual = result().unwrap_err().to_string(); 78 | 79 | // In general different rustc versions will format the interpolated lhs and 80 | // rhs $:expr fragment with insignificant differences in whitespace or 81 | // punctuation, so we check the message in full against nightly and do just 82 | // a cursory test on older toolchains. 83 | if rustversion::cfg!(nightly) && !cfg!(miri) { 84 | assert_eq!(actual, expected); 85 | } else { 86 | assert_eq!(actual.contains(" vs "), expected.contains(" vs ")); 87 | } 88 | } 89 | 90 | #[test] 91 | fn test_recursion() { 92 | // Must not blow the default #[recursion_limit], which is 128. 93 | #[rustfmt::skip] 94 | let test = || Ok(ensure!( 95 | false | false | false | false | false | false | false | false | false | 96 | false | false | false | false | false | false | false | false | false | 97 | false | false | false | false | false | false | false | false | false | 98 | false | false | false | false | false | false | false | false | false | 99 | false | false | false | false | false | false | false | false | false | 100 | false | false | false | false | false | false | false | false | false | 101 | false | false | false | false | false | false | false | false | false 102 | )); 103 | 104 | test().unwrap_err(); 105 | } 106 | 107 | #[test] 108 | fn test_low_precedence_control_flow() { 109 | #[allow(unreachable_code)] 110 | let test = || { 111 | let val = loop { 112 | // Break has lower precedence than the comparison operators so the 113 | // expression here is `S + (break (1 == 1))`. It would be bad if the 114 | // ensure macro partitioned this input into `(S + break 1) == (1)` 115 | // because that means a different thing than what was written. 116 | ensure!(S + break 1 == 1); 117 | }; 118 | Ok(val) 119 | }; 120 | 121 | assert!(test().unwrap()); 122 | } 123 | 124 | #[test] 125 | fn test_low_precedence_binary_operator() { 126 | // Must not partition as `false == (true && false)`. 127 | let test = || Ok(ensure!(false == true && false)); 128 | assert_err(test, "Condition failed: `false == true && false`"); 129 | 130 | // But outside the root level, it is fine. 131 | let test = || Ok(ensure!(while false == true && false {} < ())); 132 | assert_err( 133 | test, 134 | "Condition failed: `while false == true && false {} < ()` (() vs ())", 135 | ); 136 | 137 | let a = 15; 138 | let b = 3; 139 | let test = || Ok(ensure!(a <= b || a - b <= 10)); 140 | assert_err(test, "Condition failed: `a <= b || a - b <= 10`"); 141 | } 142 | 143 | #[test] 144 | fn test_high_precedence_binary_operator() { 145 | let a = 15; 146 | let b = 3; 147 | let test = || Ok(ensure!(a - b <= 10)); 148 | assert_err(test, "Condition failed: `a - b <= 10` (12 vs 10)"); 149 | } 150 | 151 | #[test] 152 | fn test_closure() { 153 | // Must not partition as `(S + move) || (1 == 1)` by treating move as an 154 | // identifier, nor as `(S + move || 1) == (1)` by misinterpreting the 155 | // closure precedence. 156 | let test = || Ok(ensure!(S + move || 1 == 1)); 157 | assert_err(test, "Condition failed: `S + move || 1 == 1`"); 158 | 159 | let test = || Ok(ensure!(S + || 1 == 1)); 160 | assert_err(test, "Condition failed: `S + || 1 == 1`"); 161 | 162 | // Must not partition as `S + ((move | ()) | 1) == 1` by treating those 163 | // pipes as bitwise-or. 164 | let test = || Ok(ensure!(S + move |()| 1 == 1)); 165 | assert_err(test, "Condition failed: `S + move |()| 1 == 1`"); 166 | 167 | let test = || Ok(ensure!(S + |()| 1 == 1)); 168 | assert_err(test, "Condition failed: `S + |()| 1 == 1`"); 169 | } 170 | 171 | #[test] 172 | fn test_unary() { 173 | let mut x = &1; 174 | let test = || Ok(ensure!(*x == 2)); 175 | assert_err(test, "Condition failed: `*x == 2` (1 vs 2)"); 176 | 177 | let test = || Ok(ensure!(!x == 1)); 178 | assert_err(test, "Condition failed: `!x == 1` (-2 vs 1)"); 179 | 180 | let test = || Ok(ensure!(-x == 1)); 181 | assert_err(test, "Condition failed: `-x == 1` (-1 vs 1)"); 182 | 183 | let test = || Ok(ensure!(&x == &&2)); 184 | assert_err(test, "Condition failed: `&x == &&2` (1 vs 2)"); 185 | 186 | let test = || Ok(ensure!(&mut x == *&&mut &2)); 187 | assert_err(test, "Condition failed: `&mut x == *&&mut &2` (1 vs 2)"); 188 | } 189 | 190 | #[rustversion::since(1.82)] 191 | #[test] 192 | fn test_raw_addr() { 193 | let mut x = 1; 194 | let test = || Ok(ensure!(S + &raw const x != S + &raw mut x)); 195 | assert_err( 196 | test, 197 | "Condition failed: `S + &raw const x != S + &raw mut x` (false vs false)", 198 | ); 199 | } 200 | 201 | #[test] 202 | fn test_if() { 203 | #[rustfmt::skip] 204 | let test = || Ok(ensure!(if false {}.t(1) == 2)); 205 | assert_err(test, "Condition failed: `if false {}.t(1) == 2` (1 vs 2)"); 206 | 207 | #[rustfmt::skip] 208 | let test = || Ok(ensure!(if false {} else {}.t(1) == 2)); 209 | assert_err( 210 | test, 211 | "Condition failed: `if false {} else {}.t(1) == 2` (1 vs 2)", 212 | ); 213 | 214 | #[rustfmt::skip] 215 | let test = || Ok(ensure!(if false {} else if false {}.t(1) == 2)); 216 | assert_err( 217 | test, 218 | "Condition failed: `if false {} else if false {}.t(1) == 2` (1 vs 2)", 219 | ); 220 | 221 | #[rustfmt::skip] 222 | let test = || Ok(ensure!(if let 1 = 2 {}.t(1) == 2)); 223 | assert_err( 224 | test, 225 | "Condition failed: `if let 1 = 2 {}.t(1) == 2` (1 vs 2)", 226 | ); 227 | 228 | #[rustfmt::skip] 229 | let test = || Ok(ensure!(if let 1 | 2 = 2 {}.t(1) == 2)); 230 | assert_err( 231 | test, 232 | "Condition failed: `if let 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)", 233 | ); 234 | 235 | #[rustfmt::skip] 236 | let test = || Ok(ensure!(if let | 1 | 2 = 2 {}.t(1) == 2)); 237 | assert_err( 238 | test, 239 | "Condition failed: `if let | 1 | 2 = 2 {}.t(1) == 2` (1 vs 2)", 240 | ); 241 | } 242 | 243 | #[test] 244 | fn test_loop() { 245 | #[rustfmt::skip] 246 | let test = || Ok(ensure!(1 + loop { break 1 } == 1)); 247 | assert_err( 248 | test, 249 | "Condition failed: `1 + loop { break 1 } == 1` (2 vs 1)", 250 | ); 251 | 252 | #[rustfmt::skip] 253 | let test = || Ok(ensure!(1 + 'a: loop { break 'a 1 } == 1)); 254 | assert_err( 255 | test, 256 | "Condition failed: `1 + 'a: loop { break 'a 1 } == 1` (2 vs 1)", 257 | ); 258 | 259 | #[rustfmt::skip] 260 | let test = || Ok(ensure!(while false {}.t(1) == 2)); 261 | assert_err( 262 | test, 263 | "Condition failed: `while false {}.t(1) == 2` (1 vs 2)", 264 | ); 265 | 266 | #[rustfmt::skip] 267 | let test = || Ok(ensure!(while let None = Some(1) {}.t(1) == 2)); 268 | assert_err( 269 | test, 270 | "Condition failed: `while let None = Some(1) {}.t(1) == 2` (1 vs 2)", 271 | ); 272 | 273 | #[rustfmt::skip] 274 | let test = || Ok(ensure!(for _x in iter::once(0) {}.t(1) == 2)); 275 | assert_err( 276 | test, 277 | "Condition failed: `for _x in iter::once(0) {}.t(1) == 2` (1 vs 2)", 278 | ); 279 | 280 | #[rustfmt::skip] 281 | let test = || Ok(ensure!(for | _x in iter::once(0) {}.t(1) == 2)); 282 | assert_err( 283 | test, 284 | "Condition failed: `for | _x in iter::once(0) {}.t(1) == 2` (1 vs 2)", 285 | ); 286 | 287 | #[rustfmt::skip] 288 | let test = || Ok(ensure!(for true | false in iter::empty() {}.t(1) == 2)); 289 | assert_err( 290 | test, 291 | "Condition failed: `for true | false in iter::empty() {}.t(1) == 2` (1 vs 2)", 292 | ); 293 | } 294 | 295 | #[test] 296 | fn test_match() { 297 | #[rustfmt::skip] 298 | let test = || Ok(ensure!(match 1 == 1 { true => 1, false => 0 } == 2)); 299 | assert_err( 300 | test, 301 | "Condition failed: `match 1 == 1 { true => 1, false => 0 } == 2` (1 vs 2)", 302 | ); 303 | } 304 | 305 | #[test] 306 | fn test_atom() { 307 | let test = || Ok(ensure!([false, false].len() > 3)); 308 | assert_err( 309 | test, 310 | "Condition failed: `[false, false].len() > 3` (2 vs 3)", 311 | ); 312 | 313 | #[rustfmt::skip] 314 | let test = || Ok(ensure!({ let x = 1; x } >= 3)); 315 | assert_err(test, "Condition failed: `{ let x = 1; x } >= 3` (1 vs 3)"); 316 | 317 | let test = || Ok(ensure!(S + async { 1 } == true)); 318 | assert_err( 319 | test, 320 | "Condition failed: `S + async { 1 } == true` (false vs true)", 321 | ); 322 | 323 | let test = || Ok(ensure!(S + async move { 1 } == true)); 324 | assert_err( 325 | test, 326 | "Condition failed: `S + async move { 1 } == true` (false vs true)", 327 | ); 328 | 329 | let x = &1; 330 | let test = || Ok(ensure!(S + unsafe { ptr::read(x) } == true)); 331 | assert_err( 332 | test, 333 | "Condition failed: `S + unsafe { ptr::read(x) } == true` (false vs true)", 334 | ); 335 | } 336 | 337 | #[test] 338 | fn test_path() { 339 | let test = || Ok(ensure!(crate::S.t(1) == 2)); 340 | assert_err(test, "Condition failed: `crate::S.t(1) == 2` (1 vs 2)"); 341 | 342 | let test = || Ok(ensure!(::anyhow::Error::root_cause.t(1) == 2)); 343 | assert_err( 344 | test, 345 | "Condition failed: `::anyhow::Error::root_cause.t(1) == 2` (1 vs 2)", 346 | ); 347 | 348 | let test = || Ok(ensure!(Error::msg::<&str>.t(1) == 2)); 349 | assert_err( 350 | test, 351 | "Condition failed: `Error::msg::<&str>.t(1) == 2` (1 vs 2)", 352 | ); 353 | 354 | #[rustfmt::skip] 355 | let test = || Ok(ensure!(Error::msg::<&str,>.t(1) == 2)); 356 | assert_err( 357 | test, 358 | "Condition failed: `Error::msg::<&str,>.t(1) == 2` (1 vs 2)", 359 | ); 360 | 361 | let test = || Ok(ensure!(Error::msg::<::Owned>.t(1) == 2)); 362 | assert_err( 363 | test, 364 | "Condition failed: `Error::msg::<::Owned>.t(1) == 2` (1 vs 2)", 365 | ); 366 | 367 | let test = || Ok(ensure!(Chain::<'static>::new.t(1) == 2)); 368 | assert_err( 369 | test, 370 | "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)", 371 | ); 372 | 373 | #[rustfmt::skip] 374 | let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2)); 375 | assert_err( 376 | test, 377 | "Condition failed: `Chain::<'static,>::new.t(1) == 2` (1 vs 2)", 378 | ); 379 | 380 | fn f() {} 381 | let test = || Ok(ensure!(f::<1>() != ())); 382 | assert_err(test, "Condition failed: `f::<1>() != ()` (() vs ())"); 383 | let test = || Ok(ensure!(f::<-1>() != ())); 384 | assert_err(test, "Condition failed: `f::<-1>() != ()` (() vs ())"); 385 | 386 | fn g() {} 387 | let test = || Ok(ensure!(g::() != ())); 388 | assert_err(test, "Condition failed: `g::() != ()` (() vs ())"); 389 | let test = || Ok(ensure!(g::() != ())); 390 | assert_err(test, "Condition failed: `g::() != ()` (() vs ())"); 391 | 392 | #[derive(PartialOrd, PartialEq, Debug)] 393 | enum E<'a, T> { 394 | #[allow(dead_code)] 395 | T(&'a T), 396 | U, 397 | } 398 | 399 | #[rustfmt::skip] 400 | let test = || Ok(ensure!(E::U::<>>E::U::)); 401 | assert_err(test, "Condition failed: `E::U::<> > E::U::` (U vs U)"); 402 | 403 | #[rustfmt::skip] 404 | let test = || Ok(ensure!(E::U::>E::U)); 405 | assert_err(test, "Condition failed: `E::U:: > E::U` (U vs U)"); 406 | 407 | #[rustfmt::skip] 408 | let test = || Ok(ensure!(E::U::>E::U)); 409 | assert_err(test, "Condition failed: `E::U:: > E::U` (U vs U)"); 410 | 411 | let test = || Ok(ensure!(Generic:: != Generic)); 412 | assert_err( 413 | test, 414 | "Condition failed: `Generic:: != Generic` (Generic vs Generic)", 415 | ); 416 | 417 | let test = || Ok(ensure!(Generic:: != Generic)); 418 | assert_err( 419 | test, 420 | "Condition failed: `Generic:: != Generic` (Generic vs Generic)", 421 | ); 422 | 423 | #[rustfmt::skip] 424 | let test = || { 425 | Ok(ensure!( 426 | Generic:: != Generic 427 | )) 428 | }; 429 | assert_err( 430 | test, 431 | "Condition failed: `Generic:: != Generic` (Generic vs Generic)", 432 | ); 433 | } 434 | 435 | #[test] 436 | fn test_macro() { 437 | let test = || Ok(ensure!(anyhow!("...").to_string().len() <= 1)); 438 | assert_err( 439 | test, 440 | "Condition failed: `anyhow!(\"...\").to_string().len() <= 1` (3 vs 1)", 441 | ); 442 | 443 | let test = || Ok(ensure!(vec![1].len() < 1)); 444 | assert_err(test, "Condition failed: `vec![1].len() < 1` (1 vs 1)"); 445 | 446 | let test = || Ok(ensure!(stringify! {} != "")); 447 | assert_err( 448 | test, 449 | "Condition failed: `stringify! {} != \"\"` (\"\" vs \"\")", 450 | ); 451 | } 452 | 453 | #[test] 454 | fn test_trailer() { 455 | let test = || Ok(ensure!((|| 1)() == 2)); 456 | assert_err(test, "Condition failed: `(|| 1)() == 2` (1 vs 2)"); 457 | 458 | let test = || Ok(ensure!(b"hmm"[1] == b'c')); 459 | assert_err(test, "Condition failed: `b\"hmm\"[1] == b'c'` (109 vs 99)"); 460 | 461 | let test = || Ok(ensure!(PhantomData:: {} != PhantomData)); 462 | assert_err( 463 | test, 464 | "Condition failed: `PhantomData:: {} != PhantomData` (PhantomData vs PhantomData)", 465 | ); 466 | 467 | let result = Ok::<_, Error>(1); 468 | let test = || Ok(ensure!(result? == 2)); 469 | assert_err(test, "Condition failed: `result? == 2` (1 vs 2)"); 470 | 471 | let test = || Ok(ensure!((2, 3).1 == 2)); 472 | assert_err(test, "Condition failed: `(2, 3).1 == 2` (3 vs 2)"); 473 | 474 | #[rustfmt::skip] 475 | let test = || Ok(ensure!((2, (3, 4)). 1.1 == 2)); 476 | assert_err(test, "Condition failed: `(2, (3, 4)).1.1 == 2` (4 vs 2)"); 477 | 478 | let err = anyhow!(""); 479 | let test = || Ok(ensure!(err.is::<&str>() == false)); 480 | assert_err( 481 | test, 482 | "Condition failed: `err.is::<&str>() == false` (true vs false)", 483 | ); 484 | 485 | let test = || Ok(ensure!(err.is::<::Owned>() == true)); 486 | assert_err( 487 | test, 488 | "Condition failed: `err.is::<::Owned>() == true` (false vs true)", 489 | ); 490 | } 491 | 492 | #[test] 493 | fn test_whitespace() { 494 | #[derive(Debug)] 495 | pub struct Point { 496 | #[allow(dead_code)] 497 | pub x: i32, 498 | #[allow(dead_code)] 499 | pub y: i32, 500 | } 501 | 502 | let point = Point { x: 0, y: 0 }; 503 | let test = || Ok(ensure!("" == format!("{:#?}", point))); 504 | assert_err( 505 | test, 506 | "Condition failed: `\"\" == format!(\"{:#?}\", point)`", 507 | ); 508 | } 509 | 510 | #[test] 511 | fn test_too_long() { 512 | let test = || Ok(ensure!("" == "x".repeat(10))); 513 | assert_err( 514 | test, 515 | "Condition failed: `\"\" == \"x\".repeat(10)` (\"\" vs \"xxxxxxxxxx\")", 516 | ); 517 | 518 | let test = || Ok(ensure!("" == "x".repeat(80))); 519 | assert_err(test, "Condition failed: `\"\" == \"x\".repeat(80)`"); 520 | } 521 | 522 | #[test] 523 | fn test_as() { 524 | let test = || Ok(ensure!('\0' as u8 > 1)); 525 | assert_err(test, "Condition failed: `'\\0' as u8 > 1` (0 vs 1)"); 526 | 527 | let test = || Ok(ensure!('\0' as ::std::primitive::u8 > 1)); 528 | assert_err( 529 | test, 530 | "Condition failed: `'\\0' as ::std::primitive::u8 > 1` (0 vs 1)", 531 | ); 532 | 533 | let test = || Ok(ensure!(&[0] as &[i32] == [1])); 534 | assert_err( 535 | test, 536 | "Condition failed: `&[0] as &[i32] == [1]` ([0] vs [1])", 537 | ); 538 | 539 | let test = || Ok(ensure!(0 as *const () as *mut _ == 1 as *mut ())); 540 | assert_err( 541 | test, 542 | "Condition failed: `0 as *const () as *mut _ == 1 as *mut ()` (0x0 vs 0x1)", 543 | ); 544 | 545 | let s = ""; 546 | let test = || Ok(ensure!(s as &str != s)); 547 | assert_err(test, "Condition failed: `s as &str != s` (\"\" vs \"\")"); 548 | 549 | let test = || Ok(ensure!(&s as &&str != &s)); 550 | assert_err(test, "Condition failed: `&s as &&str != &s` (\"\" vs \"\")"); 551 | 552 | let test = || Ok(ensure!(s as &'static str != s)); 553 | assert_err( 554 | test, 555 | "Condition failed: `s as &'static str != s` (\"\" vs \"\")", 556 | ); 557 | 558 | let test = || Ok(ensure!(&s as &&'static str != &s)); 559 | assert_err( 560 | test, 561 | "Condition failed: `&s as &&'static str != &s` (\"\" vs \"\")", 562 | ); 563 | 564 | let m: &mut str = Default::default(); 565 | let test = || Ok(ensure!(m as &mut str != s)); 566 | assert_err( 567 | test, 568 | "Condition failed: `m as &mut str != s` (\"\" vs \"\")", 569 | ); 570 | 571 | let test = || Ok(ensure!(&m as &&mut str != &s)); 572 | assert_err( 573 | test, 574 | "Condition failed: `&m as &&mut str != &s` (\"\" vs \"\")", 575 | ); 576 | 577 | let test = || Ok(ensure!(&m as &&'static mut str != &s)); 578 | assert_err( 579 | test, 580 | "Condition failed: `&m as &&'static mut str != &s` (\"\" vs \"\")", 581 | ); 582 | 583 | let f = || {}; 584 | let test = || Ok(ensure!(f as fn() as usize * 0 != 0)); 585 | assert_err( 586 | test, 587 | "Condition failed: `f as fn() as usize * 0 != 0` (0 vs 0)", 588 | ); 589 | 590 | let test = || Ok(ensure!(f as fn() -> () as usize * 0 != 0)); 591 | assert_err( 592 | test, 593 | "Condition failed: `f as fn() -> () as usize * 0 != 0` (0 vs 0)", 594 | ); 595 | 596 | let test = || Ok(ensure!(f as for<'a> fn() as usize * 0 != 0)); 597 | assert_err( 598 | test, 599 | "Condition failed: `f as for<'a> fn() as usize * 0 != 0` (0 vs 0)", 600 | ); 601 | 602 | let test = || Ok(ensure!(f as unsafe fn() as usize * 0 != 0)); 603 | assert_err( 604 | test, 605 | "Condition failed: `f as unsafe fn() as usize * 0 != 0` (0 vs 0)", 606 | ); 607 | 608 | #[rustfmt::skip] 609 | let test = || Ok(ensure!(f as extern "Rust" fn() as usize * 0 != 0)); 610 | assert_err( 611 | test, 612 | "Condition failed: `f as extern \"Rust\" fn() as usize * 0 != 0` (0 vs 0)", 613 | ); 614 | 615 | extern "C" fn extern_fn() {} 616 | #[rustfmt::skip] 617 | #[allow(missing_abi)] 618 | let test = || Ok(ensure!(extern_fn as extern fn() as usize * 0 != 0)); 619 | assert_err( 620 | test, 621 | "Condition failed: `extern_fn as extern fn() as usize * 0 != 0` (0 vs 0)", 622 | ); 623 | 624 | let f = || -> ! { panic!() }; 625 | let test = || Ok(ensure!(f as fn() -> ! as usize * 0 != 0)); 626 | assert_err( 627 | test, 628 | "Condition failed: `f as fn() -> ! as usize * 0 != 0` (0 vs 0)", 629 | ); 630 | 631 | trait EqDebug: PartialEq + Debug { 632 | type Assoc; 633 | } 634 | 635 | impl EqDebug for S 636 | where 637 | S: PartialEq + Debug, 638 | { 639 | type Assoc = bool; 640 | } 641 | 642 | let test = || Ok(ensure!(&0 as &dyn EqDebug != &0)); 643 | assert_err( 644 | test, 645 | "Condition failed: `&0 as &dyn EqDebug != &0` (0 vs 0)", 646 | ); 647 | 648 | let test = || { 649 | Ok(ensure!( 650 | PhantomData as PhantomData<::Owned> != PhantomData 651 | )) 652 | }; 653 | assert_err( 654 | test, 655 | "Condition failed: `PhantomData as PhantomData<::Owned> != PhantomData` (PhantomData vs PhantomData)", 656 | ); 657 | 658 | macro_rules! int { 659 | (...) => { 660 | u8 661 | }; 662 | } 663 | 664 | let test = || Ok(ensure!(0 as int!(...) != 0)); 665 | assert_err(test, "Condition failed: `0 as int!(...) != 0` (0 vs 0)"); 666 | 667 | let test = || Ok(ensure!(0 as int![...] != 0)); 668 | assert_err(test, "Condition failed: `0 as int![...] != 0` (0 vs 0)"); 669 | 670 | let test = || Ok(ensure!(0 as int! {...} != 0)); 671 | assert_err(test, "Condition failed: `0 as int! {...} != 0` (0 vs 0)"); 672 | } 673 | 674 | #[test] 675 | fn test_pat() { 676 | let test = || Ok(ensure!(if let ref mut _x @ 0 = 0 { 0 } else { 1 } == 1)); 677 | assert_err( 678 | test, 679 | "Condition failed: `if let ref mut _x @ 0 = 0 { 0 } else { 1 } == 1` (0 vs 1)", 680 | ); 681 | 682 | let test = || Ok(ensure!(if let -1..=1 = 0 { 0 } else { 1 } == 1)); 683 | assert_err( 684 | test, 685 | "Condition failed: `if let -1..=1 = 0 { 0 } else { 1 } == 1` (0 vs 1)", 686 | ); 687 | 688 | let test = || Ok(ensure!(if let &0 = &0 { 0 } else { 1 } == 1)); 689 | assert_err( 690 | test, 691 | "Condition failed: `if let &0 = &0 { 0 } else { 1 } == 1` (0 vs 1)", 692 | ); 693 | 694 | let test = || Ok(ensure!(if let &&0 = &&0 { 0 } else { 1 } == 1)); 695 | assert_err( 696 | test, 697 | "Condition failed: `if let &&0 = &&0 { 0 } else { 1 } == 1` (0 vs 1)", 698 | ); 699 | 700 | let test = || Ok(ensure!(if let &mut 0 = &mut 0 { 0 } else { 1 } == 1)); 701 | assert_err( 702 | test, 703 | "Condition failed: `if let &mut 0 = &mut 0 { 0 } else { 1 } == 1` (0 vs 1)", 704 | ); 705 | 706 | let test = || Ok(ensure!(if let &&mut 0 = &&mut 0 { 0 } else { 1 } == 1)); 707 | assert_err( 708 | test, 709 | "Condition failed: `if let &&mut 0 = &&mut 0 { 0 } else { 1 } == 1` (0 vs 1)", 710 | ); 711 | 712 | let test = || Ok(ensure!(if let (0, 1) = (0, 1) { 0 } else { 1 } == 1)); 713 | assert_err( 714 | test, 715 | "Condition failed: `if let (0, 1) = (0, 1) { 0 } else { 1 } == 1` (0 vs 1)", 716 | ); 717 | 718 | let test = || Ok(ensure!(if let [0] = b"\0" { 0 } else { 1 } == 1)); 719 | assert_err( 720 | test, 721 | "Condition failed: `if let [0] = b\"\\0\" { 0 } else { 1 } == 1` (0 vs 1)", 722 | ); 723 | 724 | let p = PhantomData::; 725 | let test = || Ok(ensure!(if let P:: {} = p { 0 } else { 1 } == 1)); 726 | assert_err( 727 | test, 728 | "Condition failed: `if let P:: {} = p { 0 } else { 1 } == 1` (0 vs 1)", 729 | ); 730 | 731 | let test = || Ok(ensure!(if let ::std::marker::PhantomData = p {} != ())); 732 | assert_err( 733 | test, 734 | "Condition failed: `if let ::std::marker::PhantomData = p {} != ()` (() vs ())", 735 | ); 736 | 737 | let test = || Ok(ensure!(if let ::V = 0 { 0 } else { 1 } == 1)); 738 | assert_err( 739 | test, 740 | "Condition failed: `if let ::V = 0 { 0 } else { 1 } == 1` (0 vs 1)", 741 | ); 742 | 743 | let test = || Ok(ensure!(for _ in iter::once(()) {} != ())); 744 | assert_err( 745 | test, 746 | "Condition failed: `for _ in iter::once(()) {} != ()` (() vs ())", 747 | ); 748 | 749 | let test = || Ok(ensure!(if let stringify!(x) = "x" { 0 } else { 1 } == 1)); 750 | assert_err( 751 | test, 752 | "Condition failed: `if let stringify!(x) = \"x\" { 0 } else { 1 } == 1` (0 vs 1)", 753 | ); 754 | } 755 | -------------------------------------------------------------------------------- /tests/test_ffi.rs: -------------------------------------------------------------------------------- 1 | #![deny(improper_ctypes, improper_ctypes_definitions)] 2 | 3 | use anyhow::anyhow; 4 | 5 | #[no_mangle] 6 | pub extern "C" fn anyhow1(err: anyhow::Error) { 7 | println!("{:?}", err); 8 | } 9 | 10 | #[no_mangle] 11 | pub extern "C" fn anyhow2(err: &mut Option) { 12 | *err = Some(anyhow!("ffi error")); 13 | } 14 | 15 | #[no_mangle] 16 | pub extern "C" fn anyhow3() -> Option { 17 | Some(anyhow!("ffi error")) 18 | } 19 | -------------------------------------------------------------------------------- /tests/test_fmt.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Context, Result}; 2 | use std::io; 3 | 4 | fn f() -> Result<()> { 5 | bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); 6 | } 7 | 8 | fn g() -> Result<()> { 9 | f().context("f failed") 10 | } 11 | 12 | fn h() -> Result<()> { 13 | g().context("g failed") 14 | } 15 | 16 | const EXPECTED_ALTDISPLAY_F: &str = "oh no!"; 17 | 18 | const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!"; 19 | 20 | const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!"; 21 | 22 | const EXPECTED_DEBUG_F: &str = "oh no!"; 23 | 24 | const EXPECTED_DEBUG_G: &str = "\ 25 | f failed 26 | 27 | Caused by: 28 | oh no!\ 29 | "; 30 | 31 | const EXPECTED_DEBUG_H: &str = "\ 32 | g failed 33 | 34 | Caused by: 35 | 0: f failed 36 | 1: oh no!\ 37 | "; 38 | 39 | const EXPECTED_ALTDEBUG_F: &str = "\ 40 | Custom { 41 | kind: PermissionDenied, 42 | error: \"oh no!\", 43 | }\ 44 | "; 45 | 46 | const EXPECTED_ALTDEBUG_G: &str = "\ 47 | Error { 48 | context: \"f failed\", 49 | source: Custom { 50 | kind: PermissionDenied, 51 | error: \"oh no!\", 52 | }, 53 | }\ 54 | "; 55 | 56 | const EXPECTED_ALTDEBUG_H: &str = "\ 57 | Error { 58 | context: \"g failed\", 59 | source: Error { 60 | context: \"f failed\", 61 | source: Custom { 62 | kind: PermissionDenied, 63 | error: \"oh no!\", 64 | }, 65 | }, 66 | }\ 67 | "; 68 | 69 | #[test] 70 | fn test_display() { 71 | assert_eq!("g failed", h().unwrap_err().to_string()); 72 | } 73 | 74 | #[test] 75 | fn test_altdisplay() { 76 | assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err())); 77 | assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err())); 78 | assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err())); 79 | } 80 | 81 | #[test] 82 | fn test_debug() { 83 | assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err())); 84 | assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err())); 85 | assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err())); 86 | } 87 | 88 | #[test] 89 | fn test_altdebug() { 90 | assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err())); 91 | assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err())); 92 | assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err())); 93 | } 94 | -------------------------------------------------------------------------------- /tests/test_macros.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::assertions_on_result_states, 3 | clippy::eq_op, 4 | clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 5 | clippy::items_after_statements, 6 | clippy::match_single_binding, 7 | clippy::needless_pass_by_value, 8 | clippy::shadow_unrelated, 9 | clippy::wildcard_imports 10 | )] 11 | 12 | mod common; 13 | 14 | use self::common::*; 15 | use anyhow::{anyhow, ensure, Result}; 16 | use std::cell::Cell; 17 | use std::future; 18 | 19 | #[test] 20 | fn test_messages() { 21 | assert_eq!("oh no!", bail_literal().unwrap_err().to_string()); 22 | assert_eq!("oh no!", bail_fmt().unwrap_err().to_string()); 23 | assert_eq!("oh no!", bail_error().unwrap_err().to_string()); 24 | } 25 | 26 | #[test] 27 | fn test_ensure() { 28 | let f = || { 29 | ensure!(1 + 1 == 2, "This is correct"); 30 | Ok(()) 31 | }; 32 | assert!(f().is_ok()); 33 | 34 | let v = 1; 35 | let f = || { 36 | ensure!(v + v == 2, "This is correct, v: {}", v); 37 | Ok(()) 38 | }; 39 | assert!(f().is_ok()); 40 | 41 | let f = || { 42 | ensure!(v + v == 1, "This is not correct, v: {}", v); 43 | Ok(()) 44 | }; 45 | assert!(f().is_err()); 46 | 47 | let f = || { 48 | ensure!(v + v == 1); 49 | Ok(()) 50 | }; 51 | assert_eq!( 52 | f().unwrap_err().to_string(), 53 | "Condition failed: `v + v == 1` (2 vs 1)", 54 | ); 55 | } 56 | 57 | #[test] 58 | fn test_ensure_nonbool() -> Result<()> { 59 | struct Struct { 60 | condition: bool, 61 | } 62 | 63 | let s = Struct { condition: true }; 64 | match &s { 65 | Struct { condition } => ensure!(condition), // &bool 66 | } 67 | 68 | Ok(()) 69 | } 70 | 71 | #[test] 72 | fn test_temporaries() { 73 | fn require_send_sync(_: impl Send + Sync) {} 74 | 75 | require_send_sync(async { 76 | // If anyhow hasn't dropped any temporary format_args it creates by the 77 | // time it's done evaluating, those will stick around until the 78 | // semicolon, which is on the other side of the await point, making the 79 | // enclosing future non-Send. 80 | future::ready(anyhow!("...")).await; 81 | }); 82 | 83 | fn message(cell: Cell<&str>) -> &str { 84 | cell.get() 85 | } 86 | 87 | require_send_sync(async { 88 | future::ready(anyhow!(message(Cell::new("...")))).await; 89 | }); 90 | } 91 | 92 | #[test] 93 | fn test_brace_escape() { 94 | let err = anyhow!("unterminated ${{..}} expression"); 95 | assert_eq!("unterminated ${..} expression", err.to_string()); 96 | } 97 | -------------------------------------------------------------------------------- /tests/test_repr.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::extra_unused_type_parameters)] 2 | 3 | mod drop; 4 | 5 | use self::drop::{DetectDrop, Flag}; 6 | use anyhow::Error; 7 | use std::mem; 8 | 9 | #[test] 10 | fn test_error_size() { 11 | assert_eq!(mem::size_of::(), mem::size_of::()); 12 | } 13 | 14 | #[test] 15 | fn test_null_pointer_optimization() { 16 | assert_eq!(mem::size_of::>(), mem::size_of::()); 17 | } 18 | 19 | #[test] 20 | fn test_autotraits() { 21 | fn assert() {} 22 | assert::(); 23 | } 24 | 25 | #[test] 26 | fn test_drop() { 27 | let has_dropped = Flag::new(); 28 | drop(Error::new(DetectDrop::new(&has_dropped))); 29 | assert!(has_dropped.get()); 30 | } 31 | -------------------------------------------------------------------------------- /tests/test_source.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | use std::error::Error as StdError; 3 | use std::fmt::{self, Display}; 4 | use std::io; 5 | 6 | #[derive(Debug)] 7 | enum TestError { 8 | Io(io::Error), 9 | } 10 | 11 | impl Display for TestError { 12 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 13 | match self { 14 | TestError::Io(e) => Display::fmt(e, formatter), 15 | } 16 | } 17 | } 18 | 19 | impl StdError for TestError { 20 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 21 | match self { 22 | TestError::Io(io) => Some(io), 23 | } 24 | } 25 | } 26 | 27 | #[test] 28 | fn test_literal_source() { 29 | let error = anyhow!("oh no!"); 30 | assert!(error.source().is_none()); 31 | } 32 | 33 | #[test] 34 | fn test_variable_source() { 35 | let msg = "oh no!"; 36 | let error = anyhow!(msg); 37 | assert!(error.source().is_none()); 38 | 39 | let msg = msg.to_owned(); 40 | let error = anyhow!(msg); 41 | assert!(error.source().is_none()); 42 | } 43 | 44 | #[test] 45 | fn test_fmt_source() { 46 | let error = anyhow!("{} {}!", "oh", "no"); 47 | assert!(error.source().is_none()); 48 | } 49 | 50 | #[test] 51 | fn test_io_source() { 52 | let io = io::Error::new(io::ErrorKind::Other, "oh no!"); 53 | let error = anyhow!(TestError::Io(io)); 54 | assert_eq!("oh no!", error.source().unwrap().to_string()); 55 | } 56 | 57 | #[test] 58 | fn test_anyhow_from_anyhow() { 59 | let error = anyhow!("oh no!").context("context"); 60 | let error = anyhow!(error); 61 | assert_eq!("oh no!", error.source().unwrap().to_string()); 62 | } 63 | -------------------------------------------------------------------------------- /tests/ui/chained-comparison.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{ensure, Result}; 2 | 3 | fn main() -> Result<()> { 4 | // `ensure!` must not partition this into `(false) == (false == true)` 5 | // because Rust doesn't ordinarily allow this form of expression. 6 | ensure!(false == false == true); 7 | Ok(()) 8 | } 9 | -------------------------------------------------------------------------------- /tests/ui/chained-comparison.stderr: -------------------------------------------------------------------------------- 1 | error: comparison operators cannot be chained 2 | --> tests/ui/chained-comparison.rs:6:19 3 | | 4 | 6 | ensure!(false == false == true); 5 | | ^^ ^^ 6 | | 7 | help: split the comparison into two 8 | | 9 | 6 | ensure!(false == false && false == true); 10 | | ++++++++ 11 | -------------------------------------------------------------------------------- /tests/ui/empty-ensure.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{ensure, Result}; 2 | 3 | fn main() -> Result<()> { 4 | ensure!(); 5 | Ok(()) 6 | } 7 | -------------------------------------------------------------------------------- /tests/ui/empty-ensure.stderr: -------------------------------------------------------------------------------- 1 | error: unexpected end of macro invocation 2 | --> tests/ui/empty-ensure.rs:4:5 3 | | 4 | 4 | ensure!(); 5 | | ^^^^^^^^^ missing tokens in macro arguments 6 | | 7 | note: while trying to match meta-variable `$cond:expr` 8 | --> src/ensure.rs 9 | | 10 | | ($cond:expr $(,)?) => { 11 | | ^^^^^^^^^^ 12 | = note: this error originates in the macro `$crate::__parse_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info) 13 | -------------------------------------------------------------------------------- /tests/ui/ensure-nonbool.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{ensure, Result}; 2 | use std::ops::{Deref, Not}; 3 | 4 | struct Bool(bool); 5 | 6 | struct DerefBool(bool); 7 | 8 | struct NotBool(bool); 9 | 10 | impl Deref for DerefBool { 11 | type Target = bool; 12 | fn deref(&self) -> &Self::Target { 13 | &self.0 14 | } 15 | } 16 | 17 | impl Not for NotBool { 18 | type Output = bool; 19 | fn not(self) -> Self::Output { 20 | !self.0 21 | } 22 | } 23 | 24 | fn main() -> Result<()> { 25 | ensure!("..."); 26 | 27 | let mut s = Bool(true); 28 | match &mut s { 29 | Bool(cond) => ensure!(cond), 30 | } 31 | 32 | let db = DerefBool(true); 33 | ensure!(db); 34 | ensure!(&db); 35 | 36 | let nb = NotBool(true); 37 | ensure!(nb); 38 | 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /tests/ui/ensure-nonbool.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `&str: __private::not::Bool` is not satisfied 2 | --> tests/ui/ensure-nonbool.rs:25:13 3 | | 4 | 25 | ensure!("..."); 5 | | --------^^^^^- 6 | | | | 7 | | | the trait `__private::not::Bool` is not implemented for `&str` 8 | | required by a bound introduced by this call 9 | | 10 | = help: the following other types implement trait `__private::not::Bool`: 11 | &bool 12 | bool 13 | note: required by a bound in `anyhow::__private::not` 14 | --> src/lib.rs 15 | | 16 | | pub fn not(cond: impl Bool) -> bool { 17 | | ^^^^ required by this bound in `not` 18 | 19 | error[E0277]: the trait bound `&mut bool: __private::not::Bool` is not satisfied 20 | --> tests/ui/ensure-nonbool.rs:29:31 21 | | 22 | 29 | Bool(cond) => ensure!(cond), 23 | | --------^^^^- 24 | | | | 25 | | | the trait `__private::not::Bool` is not implemented for `&mut bool` 26 | | required by a bound introduced by this call 27 | | 28 | = note: `__private::not::Bool` is implemented for `&bool`, but not for `&mut bool` 29 | note: required by a bound in `anyhow::__private::not` 30 | --> src/lib.rs 31 | | 32 | | pub fn not(cond: impl Bool) -> bool { 33 | | ^^^^ required by this bound in `not` 34 | help: consider dereferencing here 35 | | 36 | 29 | Bool(cond) => ensure!(*cond), 37 | | + 38 | 39 | error[E0277]: the trait bound `DerefBool: __private::not::Bool` is not satisfied 40 | --> tests/ui/ensure-nonbool.rs:33:13 41 | | 42 | 33 | ensure!(db); 43 | | --------^^- 44 | | | | 45 | | | the trait `__private::not::Bool` is not implemented for `DerefBool` 46 | | required by a bound introduced by this call 47 | | 48 | note: required by a bound in `anyhow::__private::not` 49 | --> src/lib.rs 50 | | 51 | | pub fn not(cond: impl Bool) -> bool { 52 | | ^^^^ required by this bound in `not` 53 | help: consider dereferencing here 54 | | 55 | 33 | ensure!(*db); 56 | | + 57 | 58 | error[E0277]: the trait bound `&DerefBool: __private::not::Bool` is not satisfied 59 | --> tests/ui/ensure-nonbool.rs:34:13 60 | | 61 | 34 | ensure!(&db); 62 | | --------^^^- 63 | | | | 64 | | | the trait `__private::not::Bool` is not implemented for `&DerefBool` 65 | | required by a bound introduced by this call 66 | | 67 | note: required by a bound in `anyhow::__private::not` 68 | --> src/lib.rs 69 | | 70 | | pub fn not(cond: impl Bool) -> bool { 71 | | ^^^^ required by this bound in `not` 72 | help: consider dereferencing here 73 | | 74 | 34 | ensure!(&*db); 75 | | + 76 | 77 | error[E0277]: the trait bound `NotBool: __private::not::Bool` is not satisfied 78 | --> tests/ui/ensure-nonbool.rs:37:13 79 | | 80 | 37 | ensure!(nb); 81 | | --------^^- 82 | | | | 83 | | | the trait `__private::not::Bool` is not implemented for `NotBool` 84 | | required by a bound introduced by this call 85 | | 86 | = help: the following other types implement trait `__private::not::Bool`: 87 | &bool 88 | bool 89 | note: required by a bound in `anyhow::__private::not` 90 | --> src/lib.rs 91 | | 92 | | pub fn not(cond: impl Bool) -> bool { 93 | | ^^^^ required by this bound in `not` 94 | -------------------------------------------------------------------------------- /tests/ui/must-use.rs: -------------------------------------------------------------------------------- 1 | #![deny(unused_must_use)] 2 | 3 | use anyhow::anyhow; 4 | 5 | fn main() -> anyhow::Result<()> { 6 | if true { 7 | // meant to write bail! 8 | anyhow!("it failed"); 9 | } 10 | Ok(()) 11 | } 12 | -------------------------------------------------------------------------------- /tests/ui/must-use.stderr: -------------------------------------------------------------------------------- 1 | error: unused return value of `anyhow::__private::must_use` that must be used 2 | --> tests/ui/must-use.rs:8:9 3 | | 4 | 8 | anyhow!("it failed"); 5 | | ^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | note: the lint level is defined here 8 | --> tests/ui/must-use.rs:1:9 9 | | 10 | 1 | #![deny(unused_must_use)] 11 | | ^^^^^^^^^^^^^^^ 12 | = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) 13 | -------------------------------------------------------------------------------- /tests/ui/no-impl.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | 3 | #[derive(Debug)] 4 | struct Error; 5 | 6 | fn main() { 7 | let _ = anyhow!(Error); 8 | } 9 | -------------------------------------------------------------------------------- /tests/ui/no-impl.stderr: -------------------------------------------------------------------------------- 1 | error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its trait bounds were not satisfied 2 | --> tests/ui/no-impl.rs:7:13 3 | | 4 | 4 | struct Error; 5 | | ------------ doesn't satisfy `Error: Into`, `Error: anyhow::kind::TraitKind` or `Error: std::fmt::Display` 6 | ... 7 | 7 | let _ = anyhow!(Error); 8 | | ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds 9 | | 10 | = note: the following trait bounds were not satisfied: 11 | `Error: Into` 12 | which is required by `Error: anyhow::kind::TraitKind` 13 | `Error: std::fmt::Display` 14 | which is required by `&Error: anyhow::kind::AdhocKind` 15 | `&Error: Into` 16 | which is required by `&Error: anyhow::kind::TraitKind` 17 | note: the traits `Into` and `std::fmt::Display` must be implemented 18 | --> $RUST/core/src/fmt/mod.rs 19 | | 20 | | pub trait Display { 21 | | ^^^^^^^^^^^^^^^^^ 22 | | 23 | ::: $RUST/core/src/convert/mod.rs 24 | | 25 | | pub trait Into: Sized { 26 | | ^^^^^^^^^^^^^^^^^^^^^^^^ 27 | = help: items from traits can only be used if the trait is implemented and in scope 28 | = note: the following traits define an item `anyhow_kind`, perhaps you need to implement one of them: 29 | candidate #1: `anyhow::kind::AdhocKind` 30 | candidate #2: `anyhow::kind::BoxedKind` 31 | candidate #3: `anyhow::kind::TraitKind` 32 | = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) 33 | -------------------------------------------------------------------------------- /tests/ui/temporary-value.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | 3 | fn main() { 4 | let _ = anyhow!(&String::new()); 5 | } 6 | -------------------------------------------------------------------------------- /tests/ui/temporary-value.stderr: -------------------------------------------------------------------------------- 1 | error[E0716]: temporary value dropped while borrowed 2 | --> tests/ui/temporary-value.rs:4:22 3 | | 4 | 4 | let _ = anyhow!(&String::new()); 5 | | ---------^^^^^^^^^^^^^- 6 | | | | 7 | | | creates a temporary value which is freed while still in use 8 | | temporary value is freed at the end of this statement 9 | | argument requires that borrow lasts for `'static` 10 | -------------------------------------------------------------------------------- /tests/ui/wrong-interpolation.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Result}; 2 | 3 | fn main() -> Result<()> { 4 | bail!("{} not found"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/ui/wrong-interpolation.stderr: -------------------------------------------------------------------------------- 1 | error: 1 positional argument in format string, but no arguments were given 2 | --> tests/ui/wrong-interpolation.rs:4:12 3 | | 4 | 4 | bail!("{} not found"); 5 | | ^^ 6 | --------------------------------------------------------------------------------