anyhow-1.0.44/.cargo_vcs_info.json0000644000000001120000000000100124210ustar { "git": { "sha1": "6c97c59375b24dad08c624cf61d06338f4dc9c3e" } } anyhow-1.0.44/.clippy.toml000064400000000000000000000000200072674642500135120ustar 00000000000000msrv = "1.34.0" anyhow-1.0.44/.github/workflows/ci.yml000064400000000000000000000032330072674642500157630ustar 00000000000000name: CI on: push: pull_request: schedule: [cron: "40 1 * * *"] jobs: test: name: Rust ${{matrix.rust}} runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [nightly, beta, stable, 1.51.0, 1.50.0] steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - run: cargo test - run: cargo check --no-default-features - run: cargo check --features backtrace backtrace: name: Rust 1.42.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@1.42.0 - run: cargo check --features backtrace nostd: name: Rust 1.36.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@1.36.0 - run: cargo check --no-default-features msrv: name: Rust 1.34.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@1.34.0 - run: cargo check windows: name: Windows runs-on: windows-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@stable - run: cargo check --features backtrace clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic miri: name: Miri runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@nightly with: components: miri - run: cargo miri test anyhow-1.0.44/.gitignore000064400000000000000000000000360072674642500132360ustar 00000000000000/target **/*.rs.bk Cargo.lock anyhow-1.0.44/Cargo.toml0000644000000024370000000000100104330ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "anyhow" version = "1.0.44" authors = ["David Tolnay "] description = "Flexible concrete Error type built on std::error::Error" documentation = "https://docs.rs/anyhow" readme = "README.md" categories = ["rust-patterns"] license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/anyhow" [package.metadata.docs.rs] rustdoc-args = ["--cfg", "doc_cfg"] targets = ["x86_64-unknown-linux-gnu"] [dependencies.backtrace] version = "0.3.51" optional = true [dev-dependencies.futures] version = "0.3" default-features = false [dev-dependencies.rustversion] version = "1.0" [dev-dependencies.syn] version = "1.0" features = ["full"] [dev-dependencies.thiserror] version = "1.0" [dev-dependencies.trybuild] version = "1.0.19" features = ["diff"] [features] default = ["std"] std = [] anyhow-1.0.44/Cargo.toml.orig000064400000000000000000000014560072674642500141440ustar 00000000000000[package] name = "anyhow" version = "1.0.44" # remember to update html_root_url authors = ["David Tolnay "] edition = "2018" license = "MIT OR Apache-2.0" description = "Flexible concrete Error type built on std::error::Error" repository = "https://github.com/dtolnay/anyhow" documentation = "https://docs.rs/anyhow" readme = "README.md" categories = ["rust-patterns"] [features] default = ["std"] std = [] [dependencies] backtrace = { version = "0.3.51", optional = true } [dev-dependencies] futures = { version = "0.3", default-features = false } rustversion = "1.0" syn = { version = "1.0", features = ["full"] } thiserror = "1.0" trybuild = { version = "1.0.19", features = ["diff"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--cfg", "doc_cfg"] anyhow-1.0.44/LICENSE-APACHE000064400000000000000000000251370072674642500132030ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. anyhow-1.0.44/LICENSE-MIT000064400000000000000000000017770072674642500127170ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. anyhow-1.0.44/README.md000064400000000000000000000157710072674642500125410ustar 00000000000000Anyhow ¯\\\_(°ペ)\_/¯ ========================== [github](https://github.com/dtolnay/anyhow) [crates.io](https://crates.io/crates/anyhow) [docs.rs](https://docs.rs/anyhow) [build status](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster) This library provides [`anyhow::Error`][Error], a trait object based error type for easy idiomatic error handling in Rust applications. [Error]: https://docs.rs/anyhow/1.0/anyhow/struct.Error.html ```toml [dependencies] anyhow = "1.0" ``` *Compiler support: requires rustc 1.34+*
## Details - Use `Result`, or equivalently `anyhow::Result`, as the return type of any fallible function. Within the function, use `?` to easily propagate any error that implements the `std::error::Error` trait. ```rust use anyhow::Result; fn get_cluster_info() -> Result { let config = std::fs::read_to_string("cluster.json")?; let map: ClusterMap = serde_json::from_str(&config)?; Ok(map) } ``` - Attach context to help the person troubleshooting the error understand where things went wrong. A low-level error like "No such file or directory" can be annoying to debug without more context about what higher level step the application was in the middle of. ```rust use anyhow::{Context, Result}; fn main() -> Result<()> { ... it.detach().context("Failed to detach the important thing")?; let content = std::fs::read(path) .with_context(|| format!("Failed to read instrs from {}", path))?; ... } ``` ```console Error: Failed to read instrs from ./path/to/instrs.json Caused by: No such file or directory (os error 2) ``` - Downcasting is supported and can be by value, by shared reference, or by mutable reference as needed. ```rust // If the error was caused by redaction, then return a // tombstone instead of the content. match root_cause.downcast_ref::() { Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), None => Err(error), } ``` - If using the nightly channel, or stable with `features = ["backtrace"]`, a a backtrace is captured and printed with the error if the underlying error type does not already provide its own. In order to see backtraces, they must be enabled through the environment variables described in [`std::backtrace`]: - If you want panics and errors to both have backtraces, set `RUST_BACKTRACE=1`; - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and `RUST_LIB_BACKTRACE=0`. The tracking issue for this feature is [rust-lang/rust#53487]. [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 - Anyhow works with any error type that has an impl of `std::error::Error`, including ones defined in your crate. We do not bundle a `derive(Error)` macro but you can write the impls yourself or use a standalone macro like [thiserror]. ```rust use thiserror::Error; #[derive(Error, Debug)] pub enum FormatError { #[error("Invalid header (expected {expected:?}, got {found:?})")] InvalidHeader { expected: String, found: String, }, #[error("Missing attribute: {0}")] MissingAttribute(String), } ``` - One-off error messages can be constructed using the `anyhow!` macro, which supports string interpolation and produces an `anyhow::Error`. ```rust return Err(anyhow!("Missing attribute: {}", missing)); ``` A `bail!` macro is provided as a shorthand for the same early return. ```rust bail!("Missing attribute: {}", missing); ```
## No-std support In no_std mode, the same API is almost all available and works the same way. To depend on Anyhow in no_std mode, disable our default enabled "std" feature in Cargo.toml. A global allocator is required. ```toml [dependencies] anyhow = { version = "1.0", default-features = false } ``` Since the `?`-based error conversions would normally rely on the `std::error::Error` trait which is only available through std, no_std mode will require an explicit `.map_err(Error::msg)` when working with a non-Anyhow error type inside a function that returns Anyhow's error type.
## Comparison to failure The `anyhow::Error` type works something like `failure::Error`, but unlike failure ours is built around the standard library's `std::error::Error` trait rather than a separate trait `failure::Fail`. The standard library has adopted the necessary improvements for this to be possible as part of [RFC 2504]. [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
## Comparison to thiserror Use Anyhow if you don't care what error type your functions return, you just want it to be easy. This is common in application code. Use [thiserror] if you are a library that wants to design your own dedicated error type(s) so that on failures the caller gets exactly the information that you choose. [thiserror]: https://github.com/dtolnay/thiserror
#### License Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. anyhow-1.0.44/build.rs000064400000000000000000000060040072674642500127140ustar 00000000000000#![allow(clippy::option_if_let_else)] use std::env; use std::fs; use std::path::Path; use std::process::{Command, ExitStatus, Stdio}; use std::str; #[cfg(all(feature = "backtrace", not(feature = "std")))] compile_error! { "`backtrace` feature without `std` feature is not supported" } // This code exercises the surface area that we expect of the std Backtrace // type. If the current toolchain is able to compile it, we go ahead and use // backtrace in anyhow. const PROBE: &str = r#" #![feature(backtrace)] #![allow(dead_code)] use std::backtrace::{Backtrace, BacktraceStatus}; use std::error::Error; use std::fmt::{self, Display}; #[derive(Debug)] struct E; impl Display for E { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } } impl Error for E { fn backtrace(&self) -> Option<&Backtrace> { let backtrace = Backtrace::capture(); match backtrace.status() { BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} } unimplemented!() } } "#; fn main() { if cfg!(feature = "std") { match compile_probe() { Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"), _ => {} } } let rustc = match rustc_minor_version() { Some(rustc) => rustc, None => return, }; if rustc < 38 { println!("cargo:rustc-cfg=anyhow_no_macro_reexport"); } if rustc < 51 { println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of"); } } fn compile_probe() -> Option { let rustc = env::var_os("RUSTC")?; let out_dir = env::var_os("OUT_DIR")?; let probefile = Path::new(&out_dir).join("probe.rs"); fs::write(&probefile, PROBE).ok()?; // Make sure to pick up Cargo rustc configuration. let mut cmd = if let Some(wrapper) = env::var_os("CARGO_RUSTC_WRAPPER") { let mut cmd = Command::new(wrapper); // The wrapper's first argument is supposed to be the path to rustc. cmd.arg(rustc); cmd } else { Command::new(rustc) }; cmd.stderr(Stdio::null()) .arg("--edition=2018") .arg("--crate-name=anyhow_build") .arg("--crate-type=lib") .arg("--emit=metadata") .arg("--out-dir") .arg(out_dir) .arg(probefile); // If Cargo wants to set RUSTFLAGS, use that. if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { if !rustflags.is_empty() { for arg in rustflags.split('\x1f') { cmd.arg(arg); } } } cmd.status().ok() } fn rustc_minor_version() -> Option { let rustc = env::var_os("RUSTC")?; let output = Command::new(rustc).arg("--version").output().ok()?; let version = str::from_utf8(&output.stdout).ok()?; let mut pieces = version.split('.'); if pieces.next() != Some("rustc 1") { return None; } pieces.next()?.parse().ok() } anyhow-1.0.44/src/backtrace.rs000064400000000000000000000310020072674642500143170ustar 00000000000000#[cfg(backtrace)] pub(crate) use std::backtrace::{Backtrace, BacktraceStatus}; #[cfg(all(not(backtrace), feature = "backtrace"))] pub(crate) use self::capture::{Backtrace, BacktraceStatus}; #[cfg(not(any(backtrace, feature = "backtrace")))] pub(crate) enum Backtrace {} #[cfg(backtrace)] macro_rules! impl_backtrace { () => { std::backtrace::Backtrace }; } #[cfg(all(not(backtrace), feature = "backtrace"))] macro_rules! impl_backtrace { () => { impl core::fmt::Debug + core::fmt::Display }; } #[cfg(any(backtrace, feature = "backtrace"))] macro_rules! backtrace { () => { Some(crate::backtrace::Backtrace::capture()) }; } #[cfg(not(any(backtrace, feature = "backtrace")))] macro_rules! backtrace { () => { None }; } #[cfg(backtrace)] macro_rules! backtrace_if_absent { ($err:expr) => { match $err.backtrace() { Some(_) => None, None => backtrace!(), } }; } #[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))] macro_rules! backtrace_if_absent { ($err:expr) => { backtrace!() }; } #[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))] macro_rules! backtrace_if_absent { ($err:expr) => { None }; } #[cfg(all(not(backtrace), feature = "backtrace"))] mod capture { use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName}; use core::cell::UnsafeCell; use core::fmt::{self, Debug, Display}; use core::sync::atomic::{AtomicUsize, Ordering}; use std::borrow::Cow; use std::env; use std::path::{self, Path, PathBuf}; use std::sync::Once; pub(crate) struct Backtrace { inner: Inner, } pub(crate) enum BacktraceStatus { Unsupported, Disabled, Captured, } enum Inner { Unsupported, Disabled, Captured(LazilyResolvedCapture), } struct Capture { actual_start: usize, resolved: bool, frames: Vec, } struct BacktraceFrame { frame: Frame, symbols: Vec, } struct BacktraceSymbol { name: Option>, filename: Option, lineno: Option, colno: Option, } enum BytesOrWide { Bytes(Vec), Wide(Vec), } impl Debug for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let capture = match &self.inner { Inner::Unsupported => return fmt.write_str(""), Inner::Disabled => return fmt.write_str(""), Inner::Captured(c) => c.force(), }; let frames = &capture.frames[capture.actual_start..]; write!(fmt, "Backtrace ")?; let mut dbg = fmt.debug_list(); for frame in frames { if frame.frame.ip().is_null() { continue; } dbg.entries(&frame.symbols); } dbg.finish() } } impl Debug for BacktraceFrame { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut dbg = fmt.debug_list(); dbg.entries(&self.symbols); dbg.finish() } } impl Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{{ ")?; if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) { write!(fmt, "fn: \"{:#}\"", fn_name)?; } else { write!(fmt, "fn: ")?; } if let Some(fname) = self.filename.as_ref() { write!(fmt, ", file: \"{:?}\"", fname)?; } if let Some(line) = self.lineno { write!(fmt, ", line: {:?}", line)?; } write!(fmt, " }}") } } impl Debug for BytesOrWide { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { output_filename( fmt, match self { BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), }, PrintFmt::Short, env::current_dir().as_ref().ok(), ) } } impl Backtrace { fn enabled() -> bool { static ENABLED: AtomicUsize = AtomicUsize::new(0); match ENABLED.load(Ordering::SeqCst) { 0 => {} 1 => return false, _ => return true, } let enabled = match env::var_os("RUST_LIB_BACKTRACE") { Some(s) => s != "0", None => match env::var_os("RUST_BACKTRACE") { Some(s) => s != "0", None => false, }, }; ENABLED.store(enabled as usize + 1, Ordering::SeqCst); enabled } #[inline(never)] // want to make sure there's a frame here to remove pub(crate) fn capture() -> Backtrace { if Backtrace::enabled() { Backtrace::create(Backtrace::capture as usize) } else { let inner = Inner::Disabled; Backtrace { inner } } } // Capture a backtrace which starts just before the function addressed // by `ip` fn create(ip: usize) -> Backtrace { let mut frames = Vec::new(); let mut actual_start = None; backtrace::trace(|frame| { frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new(), }); if frame.symbol_address() as usize == ip && actual_start.is_none() { actual_start = Some(frames.len() + 1); } true }); // If no frames came out assume that this is an unsupported platform // since `backtrace` doesn't provide a way of learning this right // now, and this should be a good enough approximation. let inner = if frames.is_empty() { Inner::Unsupported } else { Inner::Captured(LazilyResolvedCapture::new(Capture { actual_start: actual_start.unwrap_or(0), frames, resolved: false, })) }; Backtrace { inner } } pub(crate) fn status(&self) -> BacktraceStatus { match self.inner { Inner::Unsupported => BacktraceStatus::Unsupported, Inner::Disabled => BacktraceStatus::Disabled, Inner::Captured(_) => BacktraceStatus::Captured, } } } impl Display for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let capture = match &self.inner { Inner::Unsupported => return fmt.write_str("unsupported backtrace"), Inner::Disabled => return fmt.write_str("disabled backtrace"), Inner::Captured(c) => c.force(), }; let full = fmt.alternate(); let (frames, style) = if full { (&capture.frames[..], PrintFmt::Full) } else { (&capture.frames[capture.actual_start..], PrintFmt::Short) }; // When printing paths we try to strip the cwd if it exists, // otherwise we just print the path as-is. Note that we also only do // this for the short format, because if it's full we presumably // want to print everything. let cwd = env::current_dir(); let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| { output_filename(fmt, path, style, cwd.as_ref().ok()) }; let mut f = BacktraceFmt::new(fmt, style, &mut print_path); f.add_context()?; for frame in frames { let mut f = f.frame(); if frame.symbols.is_empty() { f.print_raw(frame.frame.ip(), None, None, None)?; } else { for symbol in frame.symbols.iter() { f.print_raw_with_column( frame.frame.ip(), symbol.name.as_ref().map(|b| SymbolName::new(b)), symbol.filename.as_ref().map(|b| match b { BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), }), symbol.lineno, symbol.colno, )?; } } } f.finish()?; Ok(()) } } struct LazilyResolvedCapture { sync: Once, capture: UnsafeCell, } impl LazilyResolvedCapture { fn new(capture: Capture) -> Self { LazilyResolvedCapture { sync: Once::new(), capture: UnsafeCell::new(capture), } } fn force(&self) -> &Capture { self.sync.call_once(|| { // Safety: This exclusive reference can't overlap with any // others. `Once` guarantees callers will block until this // closure returns. `Once` also guarantees only a single caller // will enter this closure. unsafe { &mut *self.capture.get() }.resolve(); }); // Safety: This shared reference can't overlap with the exclusive // reference above. unsafe { &*self.capture.get() } } } // Safety: Access to the inner value is synchronized using a thread-safe // `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {} impl Capture { fn resolve(&mut self) { // If we're already resolved, nothing to do! if self.resolved { return; } self.resolved = true; for frame in self.frames.iter_mut() { let symbols = &mut frame.symbols; let frame = &frame.frame; backtrace::resolve_frame(frame, |symbol| { symbols.push(BacktraceSymbol { name: symbol.name().map(|m| m.as_bytes().to_vec()), filename: symbol.filename_raw().map(|b| match b { BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), }), lineno: symbol.lineno(), colno: symbol.colno(), }); }); } } } // Prints the filename of the backtrace frame. fn output_filename( fmt: &mut fmt::Formatter, bows: BytesOrWideString, print_fmt: PrintFmt, cwd: Option<&PathBuf>, ) -> fmt::Result { let file: Cow = match bows { #[cfg(unix)] BytesOrWideString::Bytes(bytes) => { use std::os::unix::ffi::OsStrExt; Path::new(std::ffi::OsStr::from_bytes(bytes)).into() } #[cfg(not(unix))] BytesOrWideString::Bytes(bytes) => { Path::new(std::str::from_utf8(bytes).unwrap_or("")).into() } #[cfg(windows)] BytesOrWideString::Wide(wide) => { use std::os::windows::ffi::OsStringExt; Cow::Owned(std::ffi::OsString::from_wide(wide).into()) } #[cfg(not(windows))] BytesOrWideString::Wide(_wide) => Path::new("").into(), }; if print_fmt == PrintFmt::Short && file.is_absolute() { if let Some(cwd) = cwd { if let Ok(stripped) = file.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s); } } } } Display::fmt(&file.display(), fmt) } } fn _assert_send_sync() { fn _assert() {} _assert::(); } anyhow-1.0.44/src/chain.rs000064400000000000000000000046310072674642500134720ustar 00000000000000use self::ChainState::*; use crate::StdError; #[cfg(feature = "std")] use std::vec; #[cfg(feature = "std")] pub(crate) use crate::Chain; #[cfg(not(feature = "std"))] pub(crate) struct Chain<'a> { state: ChainState<'a>, } #[derive(Clone)] pub(crate) enum ChainState<'a> { Linked { next: Option<&'a (dyn StdError + 'static)>, }, #[cfg(feature = "std")] Buffered { rest: vec::IntoIter<&'a (dyn StdError + 'static)>, }, } impl<'a> Chain<'a> { #[cold] pub fn new(head: &'a (dyn StdError + 'static)) -> Self { Chain { state: ChainState::Linked { next: Some(head) }, } } } impl<'a> Iterator for Chain<'a> { type Item = &'a (dyn StdError + 'static); fn next(&mut self) -> Option { match &mut self.state { Linked { next } => { let error = (*next)?; *next = error.source(); Some(error) } #[cfg(feature = "std")] Buffered { rest } => rest.next(), } } fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } } #[cfg(feature = "std")] impl DoubleEndedIterator for Chain<'_> { fn next_back(&mut self) -> Option { match &mut self.state { Linked { mut next } => { let mut rest = Vec::new(); while let Some(cause) = next { next = cause.source(); rest.push(cause); } let mut rest = rest.into_iter(); let last = rest.next_back(); self.state = Buffered { rest }; last } Buffered { rest } => rest.next_back(), } } } impl ExactSizeIterator for Chain<'_> { fn len(&self) -> usize { match &self.state { Linked { mut next } => { let mut len = 0; while let Some(cause) = next { next = cause.source(); len += 1; } len } #[cfg(feature = "std")] Buffered { rest } => rest.len(), } } } #[cfg(feature = "std")] impl Default for Chain<'_> { fn default() -> Self { Chain { state: ChainState::Buffered { rest: Vec::new().into_iter(), }, } } } anyhow-1.0.44/src/context.rs000064400000000000000000000077500072674642500141010ustar 00000000000000use crate::error::ContextError; use crate::{Context, Error, StdError}; use core::convert::Infallible; use core::fmt::{self, Debug, Display, Write}; #[cfg(backtrace)] use std::backtrace::Backtrace; mod ext { use super::*; pub trait StdError { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static; } #[cfg(feature = "std")] impl StdError for E where E: std::error::Error + Send + Sync + 'static, { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static, { let backtrace = backtrace_if_absent!(self); Error::from_context(context, self, backtrace) } } impl StdError for Error { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static, { self.context(context) } } } impl Context for Result where E: ext::StdError + Send + Sync + 'static, { fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static, { self.map_err(|error| error.ext_context(context)) } fn with_context(self, context: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C, { self.map_err(|error| error.ext_context(context())) } } /// ``` /// # type T = (); /// # /// use anyhow::{Context, Result}; /// /// fn maybe_get() -> Option { /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unimplemented!() /// } /// /// fn demo() -> Result<()> { /// let t = maybe_get().context("there is no T")?; /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unimplemented!() /// } /// ``` impl Context for Option { fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static, { self.ok_or_else(|| Error::from_display(context, backtrace!())) } fn with_context(self, context: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C, { self.ok_or_else(|| Error::from_display(context(), backtrace!())) } } impl Debug for ContextError where C: Display, E: Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Error") .field("context", &Quoted(&self.context)) .field("source", &self.error) .finish() } } impl Display for ContextError where C: Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.context, f) } } impl StdError for ContextError where C: Display, E: StdError + 'static, { #[cfg(backtrace)] fn backtrace(&self) -> Option<&Backtrace> { self.error.backtrace() } fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.error) } } impl StdError for ContextError where C: Display, { #[cfg(backtrace)] fn backtrace(&self) -> Option<&Backtrace> { Some(self.error.backtrace()) } fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) }) } } struct Quoted(C); impl Debug for Quoted where C: Display, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_char('"')?; Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; formatter.write_char('"')?; Ok(()) } } impl Write for Quoted<&mut fmt::Formatter<'_>> { fn write_str(&mut self, s: &str) -> fmt::Result { Display::fmt(&s.escape_debug(), self.0) } } pub(crate) mod private { use super::*; pub trait Sealed {} impl Sealed for Result where E: ext::StdError {} impl Sealed for Option {} } anyhow-1.0.44/src/error.rs000064400000000000000000001016570072674642500135470ustar 00000000000000use crate::alloc::Box; use crate::backtrace::Backtrace; use crate::chain::Chain; #[cfg(any(feature = "std", anyhow_no_ptr_addr_of))] use crate::ptr::Mut; use crate::ptr::{Own, Ref}; use crate::{Error, StdError}; use core::any::TypeId; use core::fmt::{self, Debug, Display}; use core::mem::ManuallyDrop; #[cfg(not(anyhow_no_ptr_addr_of))] use core::ptr; use core::ptr::NonNull; #[cfg(feature = "std")] use core::ops::{Deref, DerefMut}; impl Error { /// Create a new error object from any error type. /// /// The error type must be threadsafe and `'static`, so that the `Error` /// will be as well. /// /// If the error type does not provide a backtrace, a backtrace will be /// created here to ensure that a backtrace exists. #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[cold] pub fn new(error: E) -> Self where E: StdError + Send + Sync + 'static, { let backtrace = backtrace_if_absent!(error); Error::from_std(error, backtrace) } /// Create a new error object from a printable error message. /// /// If the argument implements std::error::Error, prefer `Error::new` /// instead which preserves the underlying error's cause chain and /// backtrace. If the argument may or may not implement std::error::Error /// now or in the future, use `anyhow!(err)` which handles either way /// correctly. /// /// `Error::msg("...")` is equivalent to `anyhow!("...")` but occasionally /// convenient in places where a function is preferable over a macro, such /// as iterator or stream combinators: /// /// ``` /// # mod ffi { /// # pub struct Input; /// # pub struct Output; /// # pub async fn do_some_work(_: Input) -> Result { /// # unimplemented!() /// # } /// # } /// # /// # use ffi::{Input, Output}; /// # /// use anyhow::{Error, Result}; /// use futures::stream::{Stream, StreamExt, TryStreamExt}; /// /// async fn demo(stream: S) -> Result> /// where /// S: Stream, /// { /// stream /// .then(ffi::do_some_work) // returns Result /// .map_err(Error::msg) /// .try_collect() /// .await /// } /// ``` #[cold] pub fn msg(message: M) -> Self where M: Display + Debug + Send + Sync + 'static, { Error::from_adhoc(message, backtrace!()) } #[cfg(feature = "std")] #[cold] pub(crate) fn from_std(error: E, backtrace: Option) -> Self where E: StdError + Send + Sync + 'static, { let vtable = &ErrorVTable { object_drop: object_drop::, object_ref: object_ref::, #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::, object_boxed: object_boxed::, object_downcast: object_downcast::, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: no_backtrace, }; // Safety: passing vtable that operates on the right type E. unsafe { Error::construct(error, vtable, backtrace) } } #[cold] pub(crate) fn from_adhoc(message: M, backtrace: Option) -> Self where M: Display + Debug + Send + Sync + 'static, { use crate::wrapper::MessageError; let error: MessageError = MessageError(message); let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: no_backtrace, }; // Safety: MessageError is repr(transparent) so it is okay for the // vtable to allow casting the MessageError to M. unsafe { Error::construct(error, vtable, backtrace) } } #[cold] pub(crate) fn from_display(message: M, backtrace: Option) -> Self where M: Display + Send + Sync + 'static, { use crate::wrapper::DisplayError; let error: DisplayError = DisplayError(message); let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: no_backtrace, }; // Safety: DisplayError is repr(transparent) so it is okay for the // vtable to allow casting the DisplayError to M. unsafe { Error::construct(error, vtable, backtrace) } } #[cfg(feature = "std")] #[cold] pub(crate) fn from_context(context: C, error: E, backtrace: Option) -> Self where C: Display + Send + Sync + 'static, E: StdError + Send + Sync + 'static, { let error: ContextError = ContextError { context, error }; let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: context_downcast::, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: context_downcast_mut::, object_drop_rest: context_drop_rest::, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: no_backtrace, }; // Safety: passing vtable that operates on the right type. unsafe { Error::construct(error, vtable, backtrace) } } #[cfg(feature = "std")] #[cold] pub(crate) fn from_boxed( error: Box, backtrace: Option, ) -> Self { use crate::wrapper::BoxedError; let error = BoxedError(error); let vtable = &ErrorVTable { object_drop: object_drop::, object_ref: object_ref::, #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::, object_boxed: object_boxed::, object_downcast: object_downcast::>, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::>, object_drop_rest: object_drop_front::>, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: no_backtrace, }; // Safety: BoxedError is repr(transparent) so it is okay for the vtable // to allow casting to Box. unsafe { Error::construct(error, vtable, backtrace) } } // Takes backtrace as argument rather than capturing it here so that the // user sees one fewer layer of wrapping noise in the backtrace. // // Unsafe because the given vtable must have sensible behavior on the error // value of type E. #[cold] unsafe fn construct( error: E, vtable: &'static ErrorVTable, backtrace: Option, ) -> Self where E: StdError + Send + Sync + 'static, { let inner: Box> = Box::new(ErrorImpl { vtable, backtrace, _object: error, }); // Erase the concrete type of E from the compile-time type system. This // is equivalent to the safe unsize coercion from Box> to // Box> except that the // result is a thin pointer. The necessary behavior for manipulating the // underlying ErrorImpl is preserved in the vtable provided by the // caller rather than a builtin fat pointer vtable. let inner = Own::new(inner).cast::(); Error { inner } } /// Wrap the error value with additional context. /// /// For attaching context to a `Result` as it is propagated, the /// [`Context`][crate::Context] extension trait may be more convenient than /// this function. /// /// The primary reason to use `error.context(...)` instead of /// `result.context(...)` via the `Context` trait would be if the context /// needs to depend on some data held by the underlying error: /// /// ``` /// # use std::fmt::{self, Debug, Display}; /// # /// # type T = (); /// # /// # impl std::error::Error for ParseError {} /// # impl Debug for ParseError { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { /// # unimplemented!() /// # } /// # } /// # impl Display for ParseError { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { /// # unimplemented!() /// # } /// # } /// # /// use anyhow::Result; /// use std::fs::File; /// use std::path::Path; /// /// struct ParseError { /// line: usize, /// column: usize, /// } /// /// fn parse_impl(file: File) -> Result { /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unimplemented!() /// } /// /// pub fn parse(path: impl AsRef) -> Result { /// let file = File::open(&path)?; /// parse_impl(file).map_err(|error| { /// let context = format!( /// "only the first {} lines of {} are valid", /// error.line, path.as_ref().display(), /// ); /// anyhow::Error::new(error).context(context) /// }) /// } /// ``` #[cold] pub fn context(self, context: C) -> Self where C: Display + Send + Sync + 'static, { let error: ContextError = ContextError { context, error: self, }; let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: context_chain_downcast::, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: context_chain_downcast_mut::, object_drop_rest: context_chain_drop_rest::, #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: context_backtrace::, }; // As the cause is anyhow::Error, we already have a backtrace for it. let backtrace = None; // Safety: passing vtable that operates on the right type. unsafe { Error::construct(error, vtable, backtrace) } } /// Get the backtrace for this Error. /// /// In order for the backtrace to be meaningful, one of the two environment /// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined /// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat /// expensive to capture in Rust, so we don't necessarily want to be /// capturing them all over the place all the time. /// /// - If you want panics and errors to both have backtraces, set /// `RUST_BACKTRACE=1`; /// - If you want only errors to have backtraces, set /// `RUST_LIB_BACKTRACE=1`; /// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and /// `RUST_LIB_BACKTRACE=0`. /// /// # Stability /// /// Standard library backtraces are only available on the nightly channel. /// Tracking issue: [rust-lang/rust#53487][tracking]. /// /// On stable compilers, this function is only available if the crate's /// "backtrace" feature is enabled, and will use the `backtrace` crate as /// the underlying backtrace implementation. /// /// ```toml /// [dependencies] /// anyhow = { version = "1.0", features = ["backtrace"] } /// ``` /// /// [tracking]: https://github.com/rust-lang/rust/issues/53487 #[cfg(any(backtrace, feature = "backtrace"))] #[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))] pub fn backtrace(&self) -> &impl_backtrace!() { unsafe { ErrorImpl::backtrace(self.inner.by_ref()) } } /// An iterator of the chain of source errors contained by this Error. /// /// This iterator will visit every error in the cause chain of this error /// object, beginning with the error that this error object was created /// from. /// /// # Example /// /// ``` /// use anyhow::Error; /// use std::io; /// /// pub fn underlying_io_error_kind(error: &Error) -> Option { /// for cause in error.chain() { /// if let Some(io_error) = cause.downcast_ref::() { /// return Some(io_error.kind()); /// } /// } /// None /// } /// ``` #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[cold] pub fn chain(&self) -> Chain { unsafe { ErrorImpl::chain(self.inner.by_ref()) } } /// The lowest level cause of this error — this error's cause's /// cause's cause etc. /// /// The root cause is the last error in the iterator produced by /// [`chain()`][Error::chain]. #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] pub fn root_cause(&self) -> &(dyn StdError + 'static) { self.chain().last().unwrap() } /// Returns true if `E` is the type held by this error object. /// /// For errors with context, this method returns true if `E` matches the /// type of the context `C` **or** the type of the error on which the /// context has been attached. For details about the interaction between /// context and downcasting, [see here]. /// /// [see here]: trait.Context.html#effect-on-downcasting pub fn is(&self) -> bool where E: Display + Debug + Send + Sync + 'static, { self.downcast_ref::().is_some() } /// Attempt to downcast the error object to a concrete type. pub fn downcast(mut self) -> Result where E: Display + Debug + Send + Sync + 'static, { let target = TypeId::of::(); let inner = self.inner.by_mut(); unsafe { // Use vtable to find NonNull<()> which points to a value of type E // somewhere inside the data structure. #[cfg(not(anyhow_no_ptr_addr_of))] let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) { Some(addr) => addr.by_mut().extend(), None => return Err(self), }; #[cfg(anyhow_no_ptr_addr_of)] let addr = match (vtable(inner.ptr).object_downcast_mut)(inner, target) { Some(addr) => addr.extend(), None => return Err(self), }; // Prepare to read E out of the data structure. We'll drop the rest // of the data structure separately so that E is not dropped. let outer = ManuallyDrop::new(self); // Read E from where the vtable found it. let error = addr.cast::().read(); // Drop rest of the data structure outside of E. (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target); Ok(error) } } /// Downcast this error object by reference. /// /// # Example /// /// ``` /// # use anyhow::anyhow; /// # use std::fmt::{self, Display}; /// # use std::task::Poll; /// # /// # #[derive(Debug)] /// # enum DataStoreError { /// # Censored(()), /// # } /// # /// # impl Display for DataStoreError { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { /// # unimplemented!() /// # } /// # } /// # /// # impl std::error::Error for DataStoreError {} /// # /// # const REDACTED_CONTENT: () = (); /// # /// # let error = anyhow!("..."); /// # let root_cause = &error; /// # /// # let ret = /// // If the error was caused by redaction, then return a tombstone instead /// // of the content. /// match root_cause.downcast_ref::() { /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), /// None => Err(error), /// } /// # ; /// ``` pub fn downcast_ref(&self) -> Option<&E> where E: Display + Debug + Send + Sync + 'static, { let target = TypeId::of::(); unsafe { // Use vtable to find NonNull<()> which points to a value of type E // somewhere inside the data structure. let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?; Some(addr.cast::().deref()) } } /// Downcast this error object by mutable reference. pub fn downcast_mut(&mut self) -> Option<&mut E> where E: Display + Debug + Send + Sync + 'static, { let target = TypeId::of::(); unsafe { // Use vtable to find NonNull<()> which points to a value of type E // somewhere inside the data structure. #[cfg(not(anyhow_no_ptr_addr_of))] let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut(); #[cfg(anyhow_no_ptr_addr_of)] let addr = (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target)?; Some(addr.cast::().deref_mut()) } } } #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] impl From for Error where E: StdError + Send + Sync + 'static, { #[cold] fn from(error: E) -> Self { let backtrace = backtrace_if_absent!(error); Error::from_std(error, backtrace) } } #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] impl Deref for Error { type Target = dyn StdError + Send + Sync + 'static; fn deref(&self) -> &Self::Target { unsafe { ErrorImpl::error(self.inner.by_ref()) } } } #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] impl DerefMut for Error { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { ErrorImpl::error_mut(self.inner.by_mut()) } } } impl Display for Error { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) } } } impl Debug for Error { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) } } } impl Drop for Error { fn drop(&mut self) { unsafe { // Invoke the vtable's drop behavior. (vtable(self.inner.ptr).object_drop)(self.inner); } } } struct ErrorVTable { object_drop: unsafe fn(Own), object_ref: unsafe fn(Ref) -> Ref, #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: unsafe fn(Mut) -> &mut (dyn StdError + Send + Sync + 'static), object_boxed: unsafe fn(Own) -> Box, object_downcast: unsafe fn(Ref, TypeId) -> Option>, #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: unsafe fn(Mut, TypeId) -> Option>, object_drop_rest: unsafe fn(Own, TypeId), #[cfg(all(not(backtrace), feature = "backtrace"))] object_backtrace: unsafe fn(Ref) -> Option<&Backtrace>, } // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_drop(e: Own) { // Cast back to ErrorImpl so that the allocator receives the correct // Layout to deallocate the Box's memory. let unerased = e.cast::>().boxed(); drop(unerased); } // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_drop_front(e: Own, target: TypeId) { // Drop the fields of ErrorImpl other than E as well as the Box allocation, // without dropping E itself. This is used by downcast after doing a // ptr::read to take ownership of the E. let _ = target; let unerased = e.cast::>>().boxed(); drop(unerased); } // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_ref(e: Ref) -> Ref where E: StdError + Send + Sync + 'static, { // Attach E's native StdError vtable onto a pointer to self._object. let unerased = e.cast::>(); #[cfg(not(anyhow_no_ptr_addr_of))] return Ref::from_raw(NonNull::new_unchecked( ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, )); #[cfg(anyhow_no_ptr_addr_of)] return Ref::new(&unerased.deref()._object); } // Safety: requires layout of *e to match ErrorImpl, and for `e` to be derived // from a `&mut` #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] unsafe fn object_mut(e: Mut) -> &mut (dyn StdError + Send + Sync + 'static) where E: StdError + Send + Sync + 'static, { // Attach E's native StdError vtable onto a pointer to self._object. &mut e.cast::>().deref_mut()._object } // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_boxed(e: Own) -> Box where E: StdError + Send + Sync + 'static, { // Attach ErrorImpl's native StdError vtable. The StdError impl is below. e.cast::>().boxed() } // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_downcast(e: Ref, target: TypeId) -> Option> where E: 'static, { if TypeId::of::() == target { // Caller is looking for an E pointer and e is ErrorImpl, take a // pointer to its E field. let unerased = e.cast::>(); #[cfg(not(anyhow_no_ptr_addr_of))] return Some( Ref::from_raw(NonNull::new_unchecked( ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, )) .cast::<()>(), ); #[cfg(anyhow_no_ptr_addr_of)] return Some(Ref::new(&unerased.deref()._object).cast::<()>()); } else { None } } // Safety: requires layout of *e to match ErrorImpl. #[cfg(anyhow_no_ptr_addr_of)] unsafe fn object_downcast_mut(e: Mut, target: TypeId) -> Option> where E: 'static, { if TypeId::of::() == target { // Caller is looking for an E pointer and e is ErrorImpl, take a // pointer to its E field. let unerased = e.cast::>().deref_mut(); Some(Mut::new(&mut unerased._object).cast::<()>()) } else { None } } #[cfg(all(not(backtrace), feature = "backtrace"))] fn no_backtrace(e: Ref) -> Option<&Backtrace> { let _ = e; None } // Safety: requires layout of *e to match ErrorImpl>. #[cfg(feature = "std")] unsafe fn context_downcast(e: Ref, target: TypeId) -> Option> where C: 'static, E: 'static, { if TypeId::of::() == target { let unerased = e.cast::>>().deref(); Some(Ref::new(&unerased._object.context).cast::<()>()) } else if TypeId::of::() == target { let unerased = e.cast::>>().deref(); Some(Ref::new(&unerased._object.error).cast::<()>()) } else { None } } // Safety: requires layout of *e to match ErrorImpl>. #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] unsafe fn context_downcast_mut(e: Mut, target: TypeId) -> Option> where C: 'static, E: 'static, { if TypeId::of::() == target { let unerased = e.cast::>>().deref_mut(); Some(Mut::new(&mut unerased._object.context).cast::<()>()) } else if TypeId::of::() == target { let unerased = e.cast::>>().deref_mut(); Some(Mut::new(&mut unerased._object.error).cast::<()>()) } else { None } } // Safety: requires layout of *e to match ErrorImpl>. #[cfg(feature = "std")] unsafe fn context_drop_rest(e: Own, target: TypeId) where C: 'static, E: 'static, { // Called after downcasting by value to either the C or the E and doing a // ptr::read to take ownership of that value. if TypeId::of::() == target { let unerased = e .cast::, E>>>() .boxed(); drop(unerased); } else { let unerased = e .cast::>>>() .boxed(); drop(unerased); } } // Safety: requires layout of *e to match ErrorImpl>. unsafe fn context_chain_downcast(e: Ref, target: TypeId) -> Option> where C: 'static, { let unerased = e.cast::>>().deref(); if TypeId::of::() == target { Some(Ref::new(&unerased._object.context).cast::<()>()) } else { // Recurse down the context chain per the inner error's vtable. let source = &unerased._object.error; (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) } } // Safety: requires layout of *e to match ErrorImpl>. #[cfg(anyhow_no_ptr_addr_of)] unsafe fn context_chain_downcast_mut(e: Mut, target: TypeId) -> Option> where C: 'static, { let unerased = e.cast::>>().deref_mut(); if TypeId::of::() == target { Some(Mut::new(&mut unerased._object.context).cast::<()>()) } else { // Recurse down the context chain per the inner error's vtable. let source = &mut unerased._object.error; (vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target) } } // Safety: requires layout of *e to match ErrorImpl>. unsafe fn context_chain_drop_rest(e: Own, target: TypeId) where C: 'static, { // Called after downcasting by value to either the C or one of the causes // and doing a ptr::read to take ownership of that value. if TypeId::of::() == target { let unerased = e .cast::, Error>>>() .boxed(); // Drop the entire rest of the data structure rooted in the next Error. drop(unerased); } else { let unerased = e .cast::>>>() .boxed(); // Read the Own from the next error. let inner = unerased._object.error.inner; drop(unerased); let vtable = vtable(inner.ptr); // Recursively drop the next error using the same target typeid. (vtable.object_drop_rest)(inner, target); } } // Safety: requires layout of *e to match ErrorImpl>. #[cfg(all(not(backtrace), feature = "backtrace"))] #[allow(clippy::unnecessary_wraps)] unsafe fn context_backtrace(e: Ref) -> Option<&Backtrace> where C: 'static, { let unerased = e.cast::>>().deref(); let backtrace = ErrorImpl::backtrace(unerased._object.error.inner.by_ref()); Some(backtrace) } // NOTE: If working with `ErrorImpl<()>`, references should be avoided in favor // of raw pointers and `NonNull`. // repr C to ensure that E remains in the final position. #[repr(C)] pub(crate) struct ErrorImpl { vtable: &'static ErrorVTable, backtrace: Option, // NOTE: Don't use directly. Use only through vtable. Erased type may have // different alignment. _object: E, } // Reads the vtable out of `p`. This is the same as `p.as_ref().vtable`, but // avoids converting `p` into a reference. unsafe fn vtable(p: NonNull) -> &'static ErrorVTable { // NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl. *(p.as_ptr() as *const &'static ErrorVTable) } // repr C to ensure that ContextError has the same layout as // ContextError, E> and ContextError>. #[repr(C)] pub(crate) struct ContextError { pub context: C, pub error: E, } impl ErrorImpl { fn erase(&self) -> Ref { // Erase the concrete type of E but preserve the vtable in self.vtable // for manipulating the resulting thin pointer. This is analogous to an // unsize coercion. Ref::new(self).cast::() } } impl ErrorImpl { pub(crate) unsafe fn error(this: Ref) -> &(dyn StdError + Send + Sync + 'static) { // Use vtable to attach E's native StdError vtable for the right // original type E. (vtable(this.ptr).object_ref)(this).deref() } #[cfg(feature = "std")] pub(crate) unsafe fn error_mut(this: Mut) -> &mut (dyn StdError + Send + Sync + 'static) { // Use vtable to attach E's native StdError vtable for the right // original type E. #[cfg(not(anyhow_no_ptr_addr_of))] return (vtable(this.ptr).object_ref)(this.by_ref()) .by_mut() .deref_mut(); #[cfg(anyhow_no_ptr_addr_of)] return (vtable(this.ptr).object_mut)(this); } #[cfg(any(backtrace, feature = "backtrace"))] pub(crate) unsafe fn backtrace(this: Ref) -> &Backtrace { // This unwrap can only panic if the underlying error's backtrace method // is nondeterministic, which would only happen in maliciously // constructed code. this.deref() .backtrace .as_ref() .or_else(|| { #[cfg(backtrace)] return Self::error(this).backtrace(); #[cfg(all(not(backtrace), feature = "backtrace"))] return (vtable(this.ptr).object_backtrace)(this); }) .expect("backtrace capture failed") } #[cold] pub(crate) unsafe fn chain(this: Ref) -> Chain { Chain::new(Self::error(this)) } } impl StdError for ErrorImpl where E: StdError, { #[cfg(backtrace)] fn backtrace(&self) -> Option<&Backtrace> { Some(unsafe { ErrorImpl::backtrace(self.erase()) }) } fn source(&self) -> Option<&(dyn StdError + 'static)> { unsafe { ErrorImpl::error(self.erase()).source() } } } impl Debug for ErrorImpl where E: Debug, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { unsafe { ErrorImpl::debug(self.erase(), formatter) } } } impl Display for ErrorImpl where E: Display, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { unsafe { Display::fmt(ErrorImpl::error(self.erase()), formatter) } } } impl From for Box { #[cold] fn from(error: Error) -> Self { let outer = ManuallyDrop::new(error); unsafe { // Use vtable to attach ErrorImpl's native StdError vtable for // the right original type E. (vtable(outer.inner.ptr).object_boxed)(outer.inner) } } } impl From for Box { fn from(error: Error) -> Self { Box::::from(error) } } impl From for Box { fn from(error: Error) -> Self { Box::::from(error) } } #[cfg(feature = "std")] impl AsRef for Error { fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { &**self } } #[cfg(feature = "std")] impl AsRef for Error { fn as_ref(&self) -> &(dyn StdError + 'static) { &**self } } anyhow-1.0.44/src/fmt.rs000064400000000000000000000100160072674642500131700ustar 00000000000000use crate::chain::Chain; use crate::error::ErrorImpl; use crate::ptr::Ref; use core::fmt::{self, Debug, Write}; impl ErrorImpl { pub(crate) unsafe fn display(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", Self::error(this))?; if f.alternate() { for cause in Self::chain(this).skip(1) { write!(f, ": {}", cause)?; } } Ok(()) } pub(crate) unsafe fn debug(this: Ref, f: &mut fmt::Formatter) -> fmt::Result { let error = Self::error(this); if f.alternate() { return Debug::fmt(error, f); } write!(f, "{}", error)?; if let Some(cause) = error.source() { write!(f, "\n\nCaused by:")?; let multiple = cause.source().is_some(); for (n, error) in Chain::new(cause).enumerate() { writeln!(f)?; let mut indented = Indented { inner: f, number: if multiple { Some(n) } else { None }, started: false, }; write!(indented, "{}", error)?; } } #[cfg(any(backtrace, feature = "backtrace"))] { use crate::backtrace::BacktraceStatus; let backtrace = Self::backtrace(this); if let BacktraceStatus::Captured = backtrace.status() { let mut backtrace = backtrace.to_string(); write!(f, "\n\n")?; if backtrace.starts_with("stack backtrace:") { // Capitalize to match "Caused by:" backtrace.replace_range(0..1, "S"); } else { // "stack backtrace:" prefix was removed in // https://github.com/rust-lang/backtrace-rs/pull/286 writeln!(f, "Stack backtrace:")?; } backtrace.truncate(backtrace.trim_end().len()); write!(f, "{}", backtrace)?; } } Ok(()) } } struct Indented<'a, D> { inner: &'a mut D, number: Option, started: bool, } impl Write for Indented<'_, T> where T: Write, { fn write_str(&mut self, s: &str) -> fmt::Result { for (i, line) in s.split('\n').enumerate() { if !self.started { self.started = true; match self.number { Some(number) => write!(self.inner, "{: >5}: ", number)?, None => self.inner.write_str(" ")?, } } else if i > 0 { self.inner.write_char('\n')?; if self.number.is_some() { self.inner.write_str(" ")?; } else { self.inner.write_str(" ")?; } } self.inner.write_str(line)?; } Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn one_digit() { let input = "verify\nthis"; let expected = " 2: verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: Some(2), started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } #[test] fn two_digits() { let input = "verify\nthis"; let expected = " 12: verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: Some(12), started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } #[test] fn no_digits() { let input = "verify\nthis"; let expected = " verify\n this"; let mut output = String::new(); Indented { inner: &mut output, number: None, started: false, } .write_str(input) .unwrap(); assert_eq!(expected, output); } } anyhow-1.0.44/src/kind.rs000064400000000000000000000055520072674642500133400ustar 00000000000000// Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`. // // When anyhow! is given a single expr argument to turn into anyhow::Error, we // want the resulting Error to pick up the input's implementation of source() // and backtrace() if it has a std::error::Error impl, otherwise require nothing // more than Display and Debug. // // Expressed in terms of specialization, we want something like: // // trait AnyhowNew { // fn new(self) -> Error; // } // // impl AnyhowNew for T // where // T: Display + Debug + Send + Sync + 'static, // { // default fn new(self) -> Error { // /* no std error impl */ // } // } // // impl AnyhowNew for T // where // T: std::error::Error + Send + Sync + 'static, // { // fn new(self) -> Error { // /* use std error's source() and backtrace() */ // } // } // // Since specialization is not stable yet, instead we rely on autoref behavior // of method resolution to perform tagged dispatch. Here we have two traits // AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is // implemented whether or not the caller's type has a std error impl, while // TraitKind is implemented only when a std error impl does exist. The ambiguity // is resolved by AdhocKind requiring an extra autoref so that it has lower // precedence. // // The anyhow! macro will set up the call in this form: // // #[allow(unused_imports)] // use $crate::private::{AdhocKind, TraitKind}; // let error = $msg; // (&error).anyhow_kind().new(error) use crate::Error; use core::fmt::{Debug, Display}; #[cfg(feature = "std")] use crate::StdError; pub struct Adhoc; pub trait AdhocKind: Sized { #[inline] fn anyhow_kind(&self) -> Adhoc { Adhoc } } impl AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} impl Adhoc { #[cold] pub fn new(self, message: M) -> Error where M: Display + Debug + Send + Sync + 'static, { Error::from_adhoc(message, backtrace!()) } } pub struct Trait; pub trait TraitKind: Sized { #[inline] fn anyhow_kind(&self) -> Trait { Trait } } impl TraitKind for E where E: Into {} impl Trait { #[cold] pub fn new(self, error: E) -> Error where E: Into, { error.into() } } #[cfg(feature = "std")] pub struct Boxed; #[cfg(feature = "std")] pub trait BoxedKind: Sized { #[inline] fn anyhow_kind(&self) -> Boxed { Boxed } } #[cfg(feature = "std")] impl BoxedKind for Box {} #[cfg(feature = "std")] impl Boxed { #[cold] pub fn new(self, error: Box) -> Error { let backtrace = backtrace_if_absent!(error); Error::from_boxed(error, backtrace) } } anyhow-1.0.44/src/lib.rs000064400000000000000000000472630072674642500131660ustar 00000000000000//! [![github]](https://github.com/dtolnay/anyhow) [![crates-io]](https://crates.io/crates/anyhow) [![docs-rs]](https://docs.rs/anyhow) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K //! //!
//! //! This library provides [`anyhow::Error`][Error], a trait object based error //! type for easy idiomatic error handling in Rust applications. //! //!
//! //! # Details //! //! - Use `Result`, or equivalently `anyhow::Result`, as //! the return type of any fallible function. //! //! Within the function, use `?` to easily propagate any error that implements //! the `std::error::Error` trait. //! //! ``` //! # pub trait Deserialize {} //! # //! # mod serde_json { //! # use super::Deserialize; //! # use std::io; //! # //! # pub fn from_str(json: &str) -> io::Result { //! # unimplemented!() //! # } //! # } //! # //! # struct ClusterMap; //! # //! # impl Deserialize for ClusterMap {} //! # //! use anyhow::Result; //! //! fn get_cluster_info() -> Result { //! let config = std::fs::read_to_string("cluster.json")?; //! let map: ClusterMap = serde_json::from_str(&config)?; //! Ok(map) //! } //! # //! # fn main() {} //! ``` //! //! - Attach context to help the person troubleshooting the error understand //! where things went wrong. A low-level error like "No such file or //! directory" can be annoying to debug without more context about what higher //! level step the application was in the middle of. //! //! ``` //! # struct It; //! # //! # impl It { //! # fn detach(&self) -> Result<()> { //! # unimplemented!() //! # } //! # } //! # //! use anyhow::{Context, Result}; //! //! fn main() -> Result<()> { //! # return Ok(()); //! # //! # const _: &str = stringify! { //! ... //! # }; //! # //! # let it = It; //! # let path = "./path/to/instrs.json"; //! # //! it.detach().context("Failed to detach the important thing")?; //! //! let content = std::fs::read(path) //! .with_context(|| format!("Failed to read instrs from {}", path))?; //! # //! # const _: &str = stringify! { //! ... //! # }; //! # //! # Ok(()) //! } //! ``` //! //! ```console //! Error: Failed to read instrs from ./path/to/instrs.json //! //! Caused by: //! No such file or directory (os error 2) //! ``` //! //! - Downcasting is supported and can be by value, by shared reference, or by //! mutable reference as needed. //! //! ``` //! # use anyhow::anyhow; //! # use std::fmt::{self, Display}; //! # use std::task::Poll; //! # //! # #[derive(Debug)] //! # enum DataStoreError { //! # Censored(()), //! # } //! # //! # impl Display for DataStoreError { //! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { //! # unimplemented!() //! # } //! # } //! # //! # impl std::error::Error for DataStoreError {} //! # //! # const REDACTED_CONTENT: () = (); //! # //! # let error = anyhow!("..."); //! # let root_cause = &error; //! # //! # let ret = //! // If the error was caused by redaction, then return a //! // tombstone instead of the content. //! match root_cause.downcast_ref::() { //! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), //! None => Err(error), //! } //! # ; //! ``` //! //! - If using the nightly channel, or stable with `features = ["backtrace"]`, a //! backtrace is captured and printed with the error if the underlying error //! type does not already provide its own. In order to see backtraces, they //! must be enabled through the environment variables described in //! [`std::backtrace`]: //! //! - If you want panics and errors to both have backtraces, set //! `RUST_BACKTRACE=1`; //! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; //! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and //! `RUST_LIB_BACKTRACE=0`. //! //! The tracking issue for this feature is [rust-lang/rust#53487]. //! //! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables //! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 //! //! - Anyhow works with any error type that has an impl of `std::error::Error`, //! including ones defined in your crate. We do not bundle a `derive(Error)` //! macro but you can write the impls yourself or use a standalone macro like //! [thiserror]. //! //! [thiserror]: https://github.com/dtolnay/thiserror //! //! ``` //! use thiserror::Error; //! //! #[derive(Error, Debug)] //! pub enum FormatError { //! #[error("Invalid header (expected {expected:?}, got {found:?})")] //! InvalidHeader { //! expected: String, //! found: String, //! }, //! #[error("Missing attribute: {0}")] //! MissingAttribute(String), //! } //! ``` //! //! - One-off error messages can be constructed using the `anyhow!` macro, which //! supports string interpolation and produces an `anyhow::Error`. //! //! ``` //! # use anyhow::{anyhow, Result}; //! # //! # fn demo() -> Result<()> { //! # let missing = "..."; //! return Err(anyhow!("Missing attribute: {}", missing)); //! # Ok(()) //! # } //! ``` //! //! A `bail!` macro is provided as a shorthand for the same early return. //! //! ``` //! # use anyhow::{bail, Result}; //! # //! # fn demo() -> Result<()> { //! # let missing = "..."; //! bail!("Missing attribute: {}", missing); //! # Ok(()) //! # } //! ``` //! //!
//! //! # No-std support //! //! In no_std mode, the same API is almost all available and works the same way. //! To depend on Anyhow in no_std mode, disable our default enabled "std" //! feature in Cargo.toml. A global allocator is required. //! //! ```toml //! [dependencies] //! anyhow = { version = "1.0", default-features = false } //! ``` //! //! Since the `?`-based error conversions would normally rely on the //! `std::error::Error` trait which is only available through std, no_std mode //! will require an explicit `.map_err(Error::msg)` when working with a //! non-Anyhow error type inside a function that returns Anyhow's error type. #![doc(html_root_url = "https://docs.rs/anyhow/1.0.44")] #![cfg_attr(backtrace, feature(backtrace))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr(not(feature = "std"), no_std)] #![deny(dead_code, unused_imports, unused_mut)] #![allow( clippy::doc_markdown, clippy::enum_glob_use, clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::needless_doctest_main, clippy::new_ret_no_self, clippy::redundant_else, clippy::unused_self, clippy::used_underscore_binding, clippy::wildcard_imports, clippy::wrong_self_convention )] mod alloc { #[cfg(not(feature = "std"))] extern crate alloc; #[cfg(not(feature = "std"))] pub use alloc::boxed::Box; #[cfg(feature = "std")] pub use std::boxed::Box; } #[macro_use] mod backtrace; mod chain; mod context; mod error; mod fmt; mod kind; mod macros; mod ptr; mod wrapper; use crate::error::ErrorImpl; use crate::ptr::Own; use core::fmt::Display; #[cfg(not(feature = "std"))] use core::fmt::Debug; #[cfg(feature = "std")] use std::error::Error as StdError; #[cfg(not(feature = "std"))] trait StdError: Debug + Display { fn source(&self) -> Option<&(dyn StdError + 'static)> { None } } pub use anyhow as format_err; /// The `Error` type, a wrapper around a dynamic error type. /// /// `Error` works a lot like `Box`, but with these /// differences: /// /// - `Error` requires that the error is `Send`, `Sync`, and `'static`. /// - `Error` guarantees that a backtrace is available, even if the underlying /// error type does not provide one. /// - `Error` is represented as a narrow pointer — exactly one word in /// size instead of two. /// ///
/// /// # Display representations /// /// When you print an error object using "{}" or to_string(), only the outermost /// underlying error or context is printed, not any of the lower level causes. /// This is exactly as if you had called the Display impl of the error from /// which you constructed your anyhow::Error. /// /// ```console /// Failed to read instrs from ./path/to/instrs.json /// ``` /// /// To print causes as well using anyhow's default formatting of causes, use the /// alternate selector "{:#}". /// /// ```console /// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2) /// ``` /// /// The Debug format "{:?}" includes your backtrace if one was captured. Note /// that this is the representation you get by default if you return an error /// from `fn main` instead of printing it explicitly yourself. /// /// ```console /// Error: Failed to read instrs from ./path/to/instrs.json /// /// Caused by: /// No such file or directory (os error 2) /// ``` /// /// and if there is a backtrace available: /// /// ```console /// Error: Failed to read instrs from ./path/to/instrs.json /// /// Caused by: /// No such file or directory (os error 2) /// /// Stack backtrace: /// 0: ::ext_context /// at /git/anyhow/src/backtrace.rs:26 /// 1: core::result::Result::map_err /// at /git/rustc/src/libcore/result.rs:596 /// 2: anyhow::context:: for core::result::Result>::with_context /// at /git/anyhow/src/context.rs:58 /// 3: testing::main /// at src/main.rs:5 /// 4: std::rt::lang_start /// at /git/rustc/src/libstd/rt.rs:61 /// 5: main /// 6: __libc_start_main /// 7: _start /// ``` /// /// To see a conventional struct-style Debug representation, use "{:#?}". /// /// ```console /// Error { /// context: "Failed to read instrs from ./path/to/instrs.json", /// source: Os { /// code: 2, /// kind: NotFound, /// message: "No such file or directory", /// }, /// } /// ``` /// /// If none of the built-in representations are appropriate and you would prefer /// to render the error and its cause chain yourself, it can be done something /// like this: /// /// ``` /// use anyhow::{Context, Result}; /// /// fn main() { /// if let Err(err) = try_main() { /// eprintln!("ERROR: {}", err); /// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause)); /// std::process::exit(1); /// } /// } /// /// fn try_main() -> Result<()> { /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # Ok(()) /// } /// ``` #[repr(transparent)] pub struct Error { inner: Own, } /// Iterator of a chain of source errors. /// /// This type is the iterator returned by [`Error::chain`]. /// /// # Example /// /// ``` /// use anyhow::Error; /// use std::io; /// /// pub fn underlying_io_error_kind(error: &Error) -> Option { /// for cause in error.chain() { /// if let Some(io_error) = cause.downcast_ref::() { /// return Some(io_error.kind()); /// } /// } /// None /// } /// ``` #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[derive(Clone)] pub struct Chain<'a> { state: crate::chain::ChainState<'a>, } /// `Result` /// /// This is a reasonable return type to use throughout your application but also /// for `fn main`; if you do, failures will be printed along with any /// [context][Context] and a backtrace if one was captured. /// /// `anyhow::Result` may be used with one *or* two type parameters. /// /// ```rust /// use anyhow::Result; /// /// # const IGNORE: &str = stringify! { /// fn demo1() -> Result {...} /// // ^ equivalent to std::result::Result /// /// fn demo2() -> Result {...} /// // ^ equivalent to std::result::Result /// # }; /// ``` /// /// # Example /// /// ``` /// # pub trait Deserialize {} /// # /// # mod serde_json { /// # use super::Deserialize; /// # use std::io; /// # /// # pub fn from_str(json: &str) -> io::Result { /// # unimplemented!() /// # } /// # } /// # /// # #[derive(Debug)] /// # struct ClusterMap; /// # /// # impl Deserialize for ClusterMap {} /// # /// use anyhow::Result; /// /// fn main() -> Result<()> { /// # return Ok(()); /// let config = std::fs::read_to_string("cluster.json")?; /// let map: ClusterMap = serde_json::from_str(&config)?; /// println!("cluster info: {:#?}", map); /// Ok(()) /// } /// ``` pub type Result = core::result::Result; /// Provides the `context` method for `Result`. /// /// This trait is sealed and cannot be implemented for types outside of /// `anyhow`. /// ///
/// /// # Example /// /// ``` /// use anyhow::{Context, Result}; /// use std::fs; /// use std::path::PathBuf; /// /// pub struct ImportantThing { /// path: PathBuf, /// } /// /// impl ImportantThing { /// # const IGNORE: &'static str = stringify! { /// pub fn detach(&mut self) -> Result<()> {...} /// # }; /// # fn detach(&mut self) -> Result<()> { /// # unimplemented!() /// # } /// } /// /// pub fn do_it(mut it: ImportantThing) -> Result> { /// it.detach().context("Failed to detach the important thing")?; /// /// let path = &it.path; /// let content = fs::read(path) /// .with_context(|| format!("Failed to read instrs from {}", path.display()))?; /// /// Ok(content) /// } /// ``` /// /// When printed, the outermost context would be printed first and the lower /// level underlying causes would be enumerated below. /// /// ```console /// Error: Failed to read instrs from ./path/to/instrs.json /// /// Caused by: /// No such file or directory (os error 2) /// ``` /// ///
/// /// # Effect on downcasting /// /// After attaching context of type `C` onto an error of type `E`, the resulting /// `anyhow::Error` may be downcast to `C` **or** to `E`. /// /// That is, in codebases that rely on downcasting, Anyhow's context supports /// both of the following use cases: /// /// - **Attaching context whose type is insignificant onto errors whose type /// is used in downcasts.** /// /// In other error libraries whose context is not designed this way, it can /// be risky to introduce context to existing code because new context might /// break existing working downcasts. In Anyhow, any downcast that worked /// before adding context will continue to work after you add a context, so /// you should freely add human-readable context to errors wherever it would /// be helpful. /// /// ``` /// # use anyhow::bail; /// # use thiserror::Error; /// # /// # #[derive(Error, Debug)] /// # #[error("???")] /// # struct SuspiciousError; /// # /// # fn helper() -> Result<()> { /// # bail!(SuspiciousError); /// # } /// # /// use anyhow::{Context, Result}; /// /// fn do_it() -> Result<()> { /// helper().context("Failed to complete the work")?; /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unreachable!() /// } /// /// fn main() { /// let err = do_it().unwrap_err(); /// if let Some(e) = err.downcast_ref::() { /// // If helper() returned SuspiciousError, this downcast will /// // correctly succeed even with the context in between. /// # return; /// } /// # panic!("expected downcast to succeed"); /// } /// ``` /// /// - **Attaching context whose type is used in downcasts onto errors whose /// type is insignificant.** /// /// Some codebases prefer to use machine-readable context to categorize /// lower level errors in a way that will be actionable to higher levels of /// the application. /// /// ``` /// # use anyhow::bail; /// # use thiserror::Error; /// # /// # #[derive(Error, Debug)] /// # #[error("???")] /// # struct HelperFailed; /// # /// # fn helper() -> Result<()> { /// # bail!("no such file or directory"); /// # } /// # /// use anyhow::{Context, Result}; /// /// fn do_it() -> Result<()> { /// helper().context(HelperFailed)?; /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unreachable!() /// } /// /// fn main() { /// let err = do_it().unwrap_err(); /// if let Some(e) = err.downcast_ref::() { /// // If helper failed, this downcast will succeed because /// // HelperFailed is the context that has been attached to /// // that error. /// # return; /// } /// # panic!("expected downcast to succeed"); /// } /// ``` pub trait Context: context::private::Sealed { /// Wrap the error value with additional context. fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static; /// Wrap the error value with additional context that is evaluated lazily /// only once an error does occur. fn with_context(self, f: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C; } // Not public API. Referenced by macro-generated code. #[doc(hidden)] pub mod private { use crate::Error; use core::fmt::{Debug, Display}; pub use core::result::Result::Err; #[doc(hidden)] pub mod kind { pub use crate::kind::{AdhocKind, TraitKind}; #[cfg(feature = "std")] pub use crate::kind::BoxedKind; } #[cold] pub fn new_adhoc(message: M) -> Error where M: Display + Debug + Send + Sync + 'static, { Error::from_adhoc(message, backtrace!()) } #[cfg(anyhow_no_macro_reexport)] pub use crate::{__anyhow_concat as concat, __anyhow_stringify as stringify}; #[cfg(not(anyhow_no_macro_reexport))] pub use core::{concat, stringify}; #[cfg(anyhow_no_macro_reexport)] #[doc(hidden)] #[macro_export] macro_rules! __anyhow_concat { ($($tt:tt)*) => { concat!($($tt)*) }; } #[cfg(anyhow_no_macro_reexport)] #[doc(hidden)] #[macro_export] macro_rules! __anyhow_stringify { ($($tt:tt)*) => { stringify!($($tt)*) }; } } anyhow-1.0.44/src/macros.rs000064400000000000000000000112150072674642500136700ustar 00000000000000/// Return early with an error. /// /// This macro is equivalent to `return Err(`[`anyhow!($args...)`][anyhow!]`)`. /// /// The surrounding function's or closure's return value is required to be /// `Result<_,`[`anyhow::Error`][crate::Error]`>`. /// /// # Example /// /// ``` /// # use anyhow::{bail, Result}; /// # /// # fn has_permission(user: usize, resource: usize) -> bool { /// # true /// # } /// # /// # fn main() -> Result<()> { /// # let user = 0; /// # let resource = 0; /// # /// if !has_permission(user, resource) { /// bail!("permission denied for accessing {}", resource); /// } /// # Ok(()) /// # } /// ``` /// /// ``` /// # use anyhow::{bail, Result}; /// # use thiserror::Error; /// # /// # const MAX_DEPTH: usize = 1; /// # /// #[derive(Error, Debug)] /// enum ScienceError { /// #[error("recursion limit exceeded")] /// RecursionLimitExceeded, /// # #[error("...")] /// # More = (stringify! { /// ... /// # }, 1).1, /// } /// /// # fn main() -> Result<()> { /// # let depth = 0; /// # /// if depth > MAX_DEPTH { /// bail!(ScienceError::RecursionLimitExceeded); /// } /// # Ok(()) /// # } /// ``` #[macro_export] macro_rules! bail { ($msg:literal $(,)?) => { return $crate::private::Err($crate::anyhow!($msg)) }; ($err:expr $(,)?) => { return $crate::private::Err($crate::anyhow!($err)) }; ($fmt:expr, $($arg:tt)*) => { return $crate::private::Err($crate::anyhow!($fmt, $($arg)*)) }; } /// Return early with an error if a condition is not satisfied. /// /// This macro is equivalent to `if !$cond { return /// Err(`[`anyhow!($args...)`][anyhow!]`); }`. /// /// The surrounding function's or closure's return value is required to be /// `Result<_,`[`anyhow::Error`][crate::Error]`>`. /// /// Analogously to `assert!`, `ensure!` takes a condition and exits the function /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` /// rather than panicking. /// /// # Example /// /// ``` /// # use anyhow::{ensure, Result}; /// # /// # fn main() -> Result<()> { /// # let user = 0; /// # /// ensure!(user == 0, "only user 0 is allowed"); /// # Ok(()) /// # } /// ``` /// /// ``` /// # use anyhow::{ensure, Result}; /// # use thiserror::Error; /// # /// # const MAX_DEPTH: usize = 1; /// # /// #[derive(Error, Debug)] /// enum ScienceError { /// #[error("recursion limit exceeded")] /// RecursionLimitExceeded, /// # #[error("...")] /// # More = (stringify! { /// ... /// # }, 1).1, /// } /// /// # fn main() -> Result<()> { /// # let depth = 0; /// # /// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); /// # Ok(()) /// # } /// ``` #[macro_export] macro_rules! ensure { ($cond:expr $(,)?) => { $crate::ensure!( $cond, $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`"), ) }; ($cond:expr, $msg:literal $(,)?) => { if !$cond { return $crate::private::Err($crate::anyhow!($msg)); } }; ($cond:expr, $err:expr $(,)?) => { if !$cond { return $crate::private::Err($crate::anyhow!($err)); } }; ($cond:expr, $fmt:expr, $($arg:tt)*) => { if !$cond { return $crate::private::Err($crate::anyhow!($fmt, $($arg)*)); } }; } /// Construct an ad-hoc error from a string or existing non-`anyhow` error /// value. /// /// This evaluates to an [`Error`][crate::Error]. It can take either just a /// string, or a format string with arguments. It also can take any custom type /// which implements `Debug` and `Display`. /// /// If called with a single argument whose type implements `std::error::Error` /// (in addition to `Debug` and `Display`, which are always required), then that /// Error impl's `source` is preserved as the `source` of the resulting /// `anyhow::Error`. /// /// # Example /// /// ``` /// # type V = (); /// # /// use anyhow::{anyhow, Result}; /// /// fn lookup(key: &str) -> Result { /// if key.len() != 16 { /// return Err(anyhow!("key length must be 16 characters, got {:?}", key)); /// } /// /// // ... /// # Ok(()) /// } /// ``` #[macro_export] macro_rules! anyhow { ($msg:literal $(,)?) => { // Handle $:literal as a special case to make cargo-expanded code more // concise in the common case. $crate::private::new_adhoc($msg) }; ($err:expr $(,)?) => ({ use $crate::private::kind::*; match $err { error => (&error).anyhow_kind().new(error), } }); ($fmt:expr, $($arg:tt)*) => { $crate::private::new_adhoc(format!($fmt, $($arg)*)) }; } anyhow-1.0.44/src/ptr.rs000064400000000000000000000067420072674642500132220ustar 00000000000000use crate::alloc::Box; use core::marker::PhantomData; use core::ptr::NonNull; #[repr(transparent)] pub struct Own where T: ?Sized, { pub ptr: NonNull, } unsafe impl Send for Own where T: ?Sized {} unsafe impl Sync for Own where T: ?Sized {} impl Copy for Own where T: ?Sized {} impl Clone for Own where T: ?Sized, { fn clone(&self) -> Self { *self } } impl Own where T: ?Sized, { pub fn new(ptr: Box) -> Self { Own { ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) }, } } pub fn cast(self) -> Own { Own { ptr: self.ptr.cast(), } } pub unsafe fn boxed(self) -> Box { Box::from_raw(self.ptr.as_ptr()) } pub fn by_ref(&self) -> Ref { Ref { ptr: self.ptr, lifetime: PhantomData, } } pub fn by_mut(&mut self) -> Mut { Mut { ptr: self.ptr, lifetime: PhantomData, } } } #[repr(transparent)] pub struct Ref<'a, T> where T: ?Sized, { pub ptr: NonNull, lifetime: PhantomData<&'a T>, } impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {} impl<'a, T> Clone for Ref<'a, T> where T: ?Sized, { fn clone(&self) -> Self { *self } } impl<'a, T> Ref<'a, T> where T: ?Sized, { pub fn new(ptr: &'a T) -> Self { Ref { ptr: NonNull::from(ptr), lifetime: PhantomData, } } #[cfg(not(anyhow_no_ptr_addr_of))] pub fn from_raw(ptr: NonNull) -> Self { Ref { ptr, lifetime: PhantomData, } } pub fn cast(self) -> Ref<'a, U::Target> { Ref { ptr: self.ptr.cast(), lifetime: PhantomData, } } #[cfg(not(anyhow_no_ptr_addr_of))] pub fn by_mut(self) -> Mut<'a, T> { Mut { ptr: self.ptr, lifetime: PhantomData, } } #[cfg(not(anyhow_no_ptr_addr_of))] pub fn as_ptr(self) -> *const T { self.ptr.as_ptr() as *const T } pub unsafe fn deref(self) -> &'a T { &*self.ptr.as_ptr() } } #[repr(transparent)] pub struct Mut<'a, T> where T: ?Sized, { pub ptr: NonNull, lifetime: PhantomData<&'a mut T>, } impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {} impl<'a, T> Clone for Mut<'a, T> where T: ?Sized, { fn clone(&self) -> Self { *self } } impl<'a, T> Mut<'a, T> where T: ?Sized, { #[cfg(anyhow_no_ptr_addr_of)] pub fn new(ptr: &'a mut T) -> Self { Mut { ptr: NonNull::from(ptr), lifetime: PhantomData, } } pub fn cast(self) -> Mut<'a, U::Target> { Mut { ptr: self.ptr.cast(), lifetime: PhantomData, } } #[cfg(not(anyhow_no_ptr_addr_of))] pub fn by_ref(self) -> Ref<'a, T> { Ref { ptr: self.ptr, lifetime: PhantomData, } } pub fn extend<'b>(self) -> Mut<'b, T> { Mut { ptr: self.ptr, lifetime: PhantomData, } } pub unsafe fn deref_mut(self) -> &'a mut T { &mut *self.ptr.as_ptr() } } impl<'a, T> Mut<'a, T> { pub unsafe fn read(self) -> T { self.ptr.as_ptr().read() } } // Force turbofish on all calls of `.cast::()`. pub trait CastTo { type Target; } impl CastTo for T { type Target = T; } anyhow-1.0.44/src/wrapper.rs000064400000000000000000000031660072674642500140720ustar 00000000000000use crate::StdError; use core::fmt::{self, Debug, Display}; #[repr(transparent)] pub struct MessageError(pub M); impl Debug for MessageError where M: Display + Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&self.0, f) } } impl Display for MessageError where M: Display + Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.0, f) } } impl StdError for MessageError where M: Display + Debug + 'static {} #[repr(transparent)] pub struct DisplayError(pub M); impl Debug for DisplayError where M: Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.0, f) } } impl Display for DisplayError where M: Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.0, f) } } impl StdError for DisplayError where M: Display + 'static {} #[cfg(feature = "std")] #[repr(transparent)] pub struct BoxedError(pub Box); #[cfg(feature = "std")] impl Debug for BoxedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&self.0, f) } } #[cfg(feature = "std")] impl Display for BoxedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.0, f) } } #[cfg(feature = "std")] impl StdError for BoxedError { #[cfg(backtrace)] fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> { self.0.backtrace() } fn source(&self) -> Option<&(dyn StdError + 'static)> { self.0.source() } } anyhow-1.0.44/tests/common/mod.rs000064400000000000000000000004170072674642500150300ustar 00000000000000use anyhow::{bail, Result}; use std::io; pub fn bail_literal() -> Result<()> { bail!("oh no!"); } pub fn bail_fmt() -> Result<()> { bail!("{} {}!", "oh", "no"); } pub fn bail_error() -> Result<()> { bail!(io::Error::new(io::ErrorKind::Other, "oh no!")); } anyhow-1.0.44/tests/compiletest.rs000064400000000000000000000002460072674642500153110ustar 00000000000000#[rustversion::attr(not(nightly), ignore)] #[cfg_attr(miri, ignore)] #[test] fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); } anyhow-1.0.44/tests/drop/mod.rs000064400000000000000000000020630072674642500145030ustar 00000000000000#![allow(clippy::module_name_repetitions)] use std::error::Error as StdError; use std::fmt::{self, Display}; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::SeqCst; use std::sync::Arc; #[derive(Debug)] pub struct Flag { atomic: Arc, } impl Flag { pub fn new() -> Self { Flag { atomic: Arc::new(AtomicBool::new(false)), } } pub fn get(&self) -> bool { self.atomic.load(SeqCst) } } #[derive(Debug)] pub struct DetectDrop { has_dropped: Flag, } impl DetectDrop { pub fn new(has_dropped: &Flag) -> Self { DetectDrop { has_dropped: Flag { atomic: Arc::clone(&has_dropped.atomic), }, } } } impl StdError for DetectDrop {} impl Display for DetectDrop { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "oh no!") } } impl Drop for DetectDrop { fn drop(&mut self) { let already_dropped = self.has_dropped.atomic.swap(true, SeqCst); assert!(!already_dropped); } } anyhow-1.0.44/tests/test_autotrait.rs000064400000000000000000000003050072674642500160300ustar 00000000000000use anyhow::Error; #[test] fn test_send() { fn assert_send() {} assert_send::(); } #[test] fn test_sync() { fn assert_sync() {} assert_sync::(); } anyhow-1.0.44/tests/test_backtrace.rs000064400000000000000000000003320072674642500157330ustar 00000000000000#[rustversion::not(nightly)] #[ignore] #[test] fn test_backtrace() {} #[rustversion::nightly] #[test] fn test_backtrace() { use anyhow::anyhow; let error = anyhow!("oh no!"); let _ = error.backtrace(); } anyhow-1.0.44/tests/test_boxed.rs000064400000000000000000000020430072674642500151160ustar 00000000000000#![allow( // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 clippy::nonstandard_macro_braces, )] use anyhow::anyhow; use std::error::Error as StdError; use std::io; use thiserror::Error; #[derive(Error, Debug)] #[error("outer")] struct MyError { source: io::Error, } #[test] fn test_boxed_str() { let error = Box::::from("oh no!"); let error = anyhow!(error); assert_eq!("oh no!", error.to_string()); assert_eq!( "oh no!", error .downcast_ref::>() .unwrap() .to_string() ); } #[test] fn test_boxed_thiserror() { let error = MyError { source: io::Error::new(io::ErrorKind::Other, "oh no!"), }; let error = anyhow!(error); assert_eq!("oh no!", error.source().unwrap().to_string()); } #[test] fn test_boxed_anyhow() { let error = anyhow!("oh no!").context("it failed"); let error = anyhow!(error); assert_eq!("oh no!", error.source().unwrap().to_string()); } anyhow-1.0.44/tests/test_chain.rs000064400000000000000000000041150072674642500151010ustar 00000000000000use anyhow::{anyhow, Chain, Error}; fn error() -> Error { anyhow!(0).context(1).context(2).context(3) } #[test] fn test_iter() { let e = error(); let mut chain = e.chain(); assert_eq!("3", chain.next().unwrap().to_string()); assert_eq!("2", chain.next().unwrap().to_string()); assert_eq!("1", chain.next().unwrap().to_string()); assert_eq!("0", chain.next().unwrap().to_string()); assert!(chain.next().is_none()); assert!(chain.next_back().is_none()); } #[test] fn test_rev() { let e = error(); let mut chain = e.chain().rev(); assert_eq!("0", chain.next().unwrap().to_string()); assert_eq!("1", chain.next().unwrap().to_string()); assert_eq!("2", chain.next().unwrap().to_string()); assert_eq!("3", chain.next().unwrap().to_string()); assert!(chain.next().is_none()); assert!(chain.next_back().is_none()); } #[test] fn test_len() { let e = error(); let mut chain = e.chain(); assert_eq!(4, chain.len()); assert_eq!((4, Some(4)), chain.size_hint()); assert_eq!("3", chain.next().unwrap().to_string()); assert_eq!(3, chain.len()); assert_eq!((3, Some(3)), chain.size_hint()); assert_eq!("0", chain.next_back().unwrap().to_string()); assert_eq!(2, chain.len()); assert_eq!((2, Some(2)), chain.size_hint()); assert_eq!("2", chain.next().unwrap().to_string()); assert_eq!(1, chain.len()); assert_eq!((1, Some(1)), chain.size_hint()); assert_eq!("1", chain.next_back().unwrap().to_string()); assert_eq!(0, chain.len()); assert_eq!((0, Some(0)), chain.size_hint()); assert!(chain.next().is_none()); } #[test] fn test_default() { let mut c = Chain::default(); assert!(c.next().is_none()); } #[test] fn test_clone() { let e = error(); let mut chain = e.chain().clone(); assert_eq!("3", chain.next().unwrap().to_string()); assert_eq!("2", chain.next().unwrap().to_string()); assert_eq!("1", chain.next().unwrap().to_string()); assert_eq!("0", chain.next().unwrap().to_string()); assert!(chain.next().is_none()); assert!(chain.next_back().is_none()); } anyhow-1.0.44/tests/test_context.rs000064400000000000000000000074020072674642500155050ustar 00000000000000#![allow( // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 clippy::nonstandard_macro_braces, )] mod drop; use crate::drop::{DetectDrop, Flag}; use anyhow::{Context, Error, Result}; use std::fmt::{self, Display}; use thiserror::Error; // https://github.com/dtolnay/anyhow/issues/18 #[test] fn test_inference() -> Result<()> { let x = "1"; let y: u32 = x.parse().context("...")?; assert_eq!(y, 1); Ok(()) } macro_rules! context_type { ($name:ident) => { #[derive(Debug)] struct $name { message: &'static str, drop: DetectDrop, } impl Display for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.message) } } }; } context_type!(HighLevel); context_type!(MidLevel); #[derive(Error, Debug)] #[error("{message}")] struct LowLevel { message: &'static str, drop: DetectDrop, } struct Dropped { low: Flag, mid: Flag, high: Flag, } impl Dropped { fn none(&self) -> bool { !self.low.get() && !self.mid.get() && !self.high.get() } fn all(&self) -> bool { self.low.get() && self.mid.get() && self.high.get() } } fn make_chain() -> (Error, Dropped) { let dropped = Dropped { low: Flag::new(), mid: Flag::new(), high: Flag::new(), }; let low = LowLevel { message: "no such file or directory", drop: DetectDrop::new(&dropped.low), }; // impl Context for Result let mid = Err::<(), LowLevel>(low) .context(MidLevel { message: "failed to load config", drop: DetectDrop::new(&dropped.mid), }) .unwrap_err(); // impl Context for Result let high = Err::<(), Error>(mid) .context(HighLevel { message: "failed to start server", drop: DetectDrop::new(&dropped.high), }) .unwrap_err(); (high, dropped) } #[test] fn test_downcast_ref() { let (err, dropped) = make_chain(); assert!(!err.is::()); assert!(err.downcast_ref::().is_none()); assert!(err.is::()); let high = err.downcast_ref::().unwrap(); assert_eq!(high.to_string(), "failed to start server"); assert!(err.is::()); let mid = err.downcast_ref::().unwrap(); assert_eq!(mid.to_string(), "failed to load config"); assert!(err.is::()); let low = err.downcast_ref::().unwrap(); assert_eq!(low.to_string(), "no such file or directory"); assert!(dropped.none()); drop(err); assert!(dropped.all()); } #[test] fn test_downcast_high() { let (err, dropped) = make_chain(); let err = err.downcast::().unwrap(); assert!(!dropped.high.get()); assert!(dropped.low.get() && dropped.mid.get()); drop(err); assert!(dropped.all()); } #[test] fn test_downcast_mid() { let (err, dropped) = make_chain(); let err = err.downcast::().unwrap(); assert!(!dropped.mid.get()); assert!(dropped.low.get() && dropped.high.get()); drop(err); assert!(dropped.all()); } #[test] fn test_downcast_low() { let (err, dropped) = make_chain(); let err = err.downcast::().unwrap(); assert!(!dropped.low.get()); assert!(dropped.mid.get() && dropped.high.get()); drop(err); assert!(dropped.all()); } #[test] fn test_unsuccessful_downcast() { let (err, dropped) = make_chain(); let err = err.downcast::().unwrap_err(); assert!(dropped.none()); drop(err); assert!(dropped.all()); } #[test] fn test_root_cause() { let (err, _) = make_chain(); assert_eq!(err.root_cause().to_string(), "no such file or directory"); } anyhow-1.0.44/tests/test_convert.rs000064400000000000000000000021750072674642500155030ustar 00000000000000#![allow(clippy::unnecessary_wraps)] mod drop; use self::drop::{DetectDrop, Flag}; use anyhow::{Error, Result}; use std::error::Error as StdError; #[test] fn test_convert() { let has_dropped = Flag::new(); let error = Error::new(DetectDrop::new(&has_dropped)); let box_dyn = Box::::from(error); assert_eq!("oh no!", box_dyn.to_string()); drop(box_dyn); assert!(has_dropped.get()); } #[test] fn test_convert_send() { let has_dropped = Flag::new(); let error = Error::new(DetectDrop::new(&has_dropped)); let box_dyn = Box::::from(error); assert_eq!("oh no!", box_dyn.to_string()); drop(box_dyn); assert!(has_dropped.get()); } #[test] fn test_convert_send_sync() { let has_dropped = Flag::new(); let error = Error::new(DetectDrop::new(&has_dropped)); let box_dyn = Box::::from(error); assert_eq!("oh no!", box_dyn.to_string()); drop(box_dyn); assert!(has_dropped.get()); } #[test] fn test_question_mark() -> Result<(), Box> { fn f() -> Result<()> { Ok(()) } f()?; Ok(()) } anyhow-1.0.44/tests/test_downcast.rs000064400000000000000000000057530072674642500156520ustar 00000000000000#![allow(clippy::wildcard_imports)] mod common; mod drop; use self::common::*; use self::drop::{DetectDrop, Flag}; use anyhow::Error; use std::error::Error as StdError; use std::fmt::{self, Display}; use std::io; #[test] fn test_downcast() { assert_eq!( "oh no!", bail_literal().unwrap_err().downcast::<&str>().unwrap(), ); assert_eq!( "oh no!", bail_fmt().unwrap_err().downcast::().unwrap(), ); assert_eq!( "oh no!", bail_error() .unwrap_err() .downcast::() .unwrap() .to_string(), ); } #[test] fn test_downcast_ref() { assert_eq!( "oh no!", *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(), ); assert_eq!( "oh no!", bail_fmt().unwrap_err().downcast_ref::().unwrap(), ); assert_eq!( "oh no!", bail_error() .unwrap_err() .downcast_ref::() .unwrap() .to_string(), ); } #[test] fn test_downcast_mut() { assert_eq!( "oh no!", *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(), ); assert_eq!( "oh no!", bail_fmt().unwrap_err().downcast_mut::().unwrap(), ); assert_eq!( "oh no!", bail_error() .unwrap_err() .downcast_mut::() .unwrap() .to_string(), ); let mut bailed = bail_fmt().unwrap_err(); *bailed.downcast_mut::().unwrap() = "clobber".to_string(); assert_eq!(bailed.downcast_ref::().unwrap(), "clobber"); assert_eq!(bailed.downcast_mut::().unwrap(), "clobber"); assert_eq!(bailed.downcast::().unwrap(), "clobber"); } #[test] fn test_drop() { let has_dropped = Flag::new(); let error = Error::new(DetectDrop::new(&has_dropped)); drop(error.downcast::().unwrap()); assert!(has_dropped.get()); } #[test] fn test_as_ref() { let error = bail_error().unwrap_err(); let ref_dyn: &dyn StdError = error.as_ref(); assert_eq!("oh no!", ref_dyn.to_string()); let ref_dyn_send_sync: &(dyn StdError + Send + Sync) = error.as_ref(); assert_eq!("oh no!", ref_dyn_send_sync.to_string()); } #[test] fn test_large_alignment() { #[repr(align(64))] #[derive(Debug)] struct LargeAlignedError(&'static str); impl Display for LargeAlignedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.0) } } impl StdError for LargeAlignedError {} let error = Error::new(LargeAlignedError("oh no!")); assert_eq!( "oh no!", error.downcast_ref::().unwrap().0 ); } #[test] fn test_unsuccessful_downcast() { let mut error = bail_error().unwrap_err(); assert!(error.downcast_ref::<&str>().is_none()); assert!(error.downcast_mut::<&str>().is_none()); assert!(error.downcast::<&str>().is_err()); } anyhow-1.0.44/tests/test_ffi.rs000064400000000000000000000006010072674642500145570ustar 00000000000000#![deny(improper_ctypes, improper_ctypes_definitions)] use anyhow::anyhow; #[no_mangle] pub extern "C" fn anyhow1(err: anyhow::Error) { println!("{:?}", err); } #[no_mangle] pub extern "C" fn anyhow2(err: &mut Option) { *err = Some(anyhow!("ffi error")); } #[no_mangle] pub extern "C" fn anyhow3() -> Option { Some(anyhow!("ffi error")) } anyhow-1.0.44/tests/test_fmt.rs000064400000000000000000000037260072674642500146140ustar 00000000000000use anyhow::{bail, Context, Result}; use std::io; fn f() -> Result<()> { bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); } fn g() -> Result<()> { f().context("f failed") } fn h() -> Result<()> { g().context("g failed") } const EXPECTED_ALTDISPLAY_F: &str = "oh no!"; const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!"; const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!"; const EXPECTED_DEBUG_F: &str = "oh no!"; const EXPECTED_DEBUG_G: &str = "\ f failed Caused by: oh no!\ "; const EXPECTED_DEBUG_H: &str = "\ g failed Caused by: 0: f failed 1: oh no!\ "; const EXPECTED_ALTDEBUG_F: &str = "\ Custom { kind: PermissionDenied, error: \"oh no!\", }\ "; const EXPECTED_ALTDEBUG_G: &str = "\ Error { context: \"f failed\", source: Custom { kind: PermissionDenied, error: \"oh no!\", }, }\ "; const EXPECTED_ALTDEBUG_H: &str = "\ Error { context: \"g failed\", source: Error { context: \"f failed\", source: Custom { kind: PermissionDenied, error: \"oh no!\", }, }, }\ "; #[test] fn test_display() { assert_eq!("g failed", h().unwrap_err().to_string()); } #[test] fn test_altdisplay() { assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err())); assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err())); assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err())); } #[test] #[cfg_attr(not(backtrace), ignore)] fn test_debug() { assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err())); assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err())); assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err())); } #[test] fn test_altdebug() { assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err())); assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err())); assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err())); } anyhow-1.0.44/tests/test_macros.rs000064400000000000000000000016560072674642500153120ustar 00000000000000#![allow(clippy::eq_op, clippy::shadow_unrelated, clippy::wildcard_imports)] mod common; use self::common::*; use anyhow::ensure; #[test] fn test_messages() { assert_eq!("oh no!", bail_literal().unwrap_err().to_string()); assert_eq!("oh no!", bail_fmt().unwrap_err().to_string()); assert_eq!("oh no!", bail_error().unwrap_err().to_string()); } #[test] fn test_ensure() { let f = || { ensure!(1 + 1 == 2, "This is correct"); Ok(()) }; assert!(f().is_ok()); let v = 1; let f = || { ensure!(v + v == 2, "This is correct, v: {}", v); Ok(()) }; assert!(f().is_ok()); let f = || { ensure!(v + v == 1, "This is not correct, v: {}", v); Ok(()) }; assert!(f().is_err()); let f = || { ensure!(v + v == 1); Ok(()) }; assert_eq!( f().unwrap_err().to_string(), "Condition failed: `v + v == 1`", ); } anyhow-1.0.44/tests/test_repr.rs000064400000000000000000000011150072674642500147640ustar 00000000000000mod drop; use self::drop::{DetectDrop, Flag}; use anyhow::Error; use std::marker::Unpin; use std::mem; #[test] fn test_error_size() { assert_eq!(mem::size_of::(), mem::size_of::()); } #[test] fn test_null_pointer_optimization() { assert_eq!(mem::size_of::>(), mem::size_of::()); } #[test] fn test_autotraits() { fn assert() {} assert::(); } #[test] fn test_drop() { let has_dropped = Flag::new(); drop(Error::new(DetectDrop::new(&has_dropped))); assert!(has_dropped.get()); } anyhow-1.0.44/tests/test_source.rs000064400000000000000000000025440072674642500153230ustar 00000000000000use anyhow::anyhow; use std::error::Error as StdError; use std::fmt::{self, Display}; use std::io; #[derive(Debug)] enum TestError { Io(io::Error), } impl Display for TestError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self { TestError::Io(e) => Display::fmt(e, formatter), } } } impl StdError for TestError { fn source(&self) -> Option<&(dyn StdError + 'static)> { match self { TestError::Io(io) => Some(io), } } } #[test] fn test_literal_source() { let error = anyhow!("oh no!"); assert!(error.source().is_none()); } #[test] fn test_variable_source() { let msg = "oh no!"; let error = anyhow!(msg); assert!(error.source().is_none()); let msg = msg.to_owned(); let error = anyhow!(msg); assert!(error.source().is_none()); } #[test] fn test_fmt_source() { let error = anyhow!("{} {}!", "oh", "no"); assert!(error.source().is_none()); } #[test] fn test_io_source() { let io = io::Error::new(io::ErrorKind::Other, "oh no!"); let error = anyhow!(TestError::Io(io)); assert_eq!("oh no!", error.source().unwrap().to_string()); } #[test] fn test_anyhow_from_anyhow() { let error = anyhow!("oh no!").context("context"); let error = anyhow!(error); assert_eq!("oh no!", error.source().unwrap().to_string()); } anyhow-1.0.44/tests/ui/no-impl.rs000064400000000000000000000001370072674642500147500ustar 00000000000000use anyhow::anyhow; #[derive(Debug)] struct Error; fn main() { let _ = anyhow!(Error); } anyhow-1.0.44/tests/ui/no-impl.stderr000064400000000000000000000017360072674642500156350ustar 00000000000000error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its trait bounds were not satisfied --> $DIR/no-impl.rs:7:13 | 4 | struct Error; | ------------- | | | doesn't satisfy `Error: Into` | doesn't satisfy `Error: anyhow::private::kind::TraitKind` | doesn't satisfy `Error: std::fmt::Display` ... 7 | let _ = anyhow!(Error); | ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `Error: Into` which is required by `Error: anyhow::private::kind::TraitKind` `Error: std::fmt::Display` which is required by `&Error: anyhow::private::kind::AdhocKind` `&Error: Into` which is required by `&Error: anyhow::private::kind::TraitKind` = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) anyhow-1.0.44/tests/ui/temporary-value.rs000064400000000000000000000001100072674642500165200ustar 00000000000000use anyhow::anyhow; fn main() { let _ = anyhow!(&String::new()); } anyhow-1.0.44/tests/ui/temporary-value.stderr000064400000000000000000000006170072674642500174130ustar 00000000000000error[E0716]: temporary value dropped while borrowed --> $DIR/temporary-value.rs:4:22 | 4 | let _ = anyhow!(&String::new()); | ---------^^^^^^^^^^^^^-- temporary value is freed at the end of this statement | | | | | creates a temporary which is freed while still in use | argument requires that borrow lasts for `'static`