Import failure 0.1.8 upstream upstream/0.1.8
authorWoohyun Jung <wh0705.jung@samsung.com>
Wed, 26 Apr 2023 09:01:51 +0000 (18:01 +0900)
committerWoohyun Jung <wh0705.jung@samsung.com>
Wed, 26 Apr 2023 09:01:51 +0000 (18:01 +0900)
50 files changed:
.cargo_vcs_info.json [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.gitlab-ci.yml [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
CODE_OF_CONDUCT.md [new file with mode: 0644]
Cargo.lock.ci [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
LICENSE-APACHE [new file with mode: 0644]
LICENSE-MIT [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
RELEASES.md [new file with mode: 0644]
book/src/SUMMARY.md [new file with mode: 0644]
book/src/bail-and-ensure.md [new file with mode: 0644]
book/src/custom-fail.md [new file with mode: 0644]
book/src/derive-fail.md [new file with mode: 0644]
book/src/error-errorkind.md [new file with mode: 0644]
book/src/error-msg.md [new file with mode: 0644]
book/src/error.md [new file with mode: 0644]
book/src/fail.md [new file with mode: 0644]
book/src/guidance.md [new file with mode: 0644]
book/src/howto.md [new file with mode: 0644]
book/src/intro.md [new file with mode: 0644]
book/src/string-custom-error.md [new file with mode: 0644]
book/src/use-error.md [new file with mode: 0644]
build-docs.sh [new file with mode: 0755]
examples/bail_ensure.rs [new file with mode: 0644]
examples/error_as_cause.rs [new file with mode: 0644]
examples/simple.rs [new file with mode: 0644]
examples/string_custom_error_pattern.rs [new file with mode: 0644]
src/as_fail.rs [new file with mode: 0644]
src/backtrace/internal.rs [new file with mode: 0644]
src/backtrace/mod.rs [new file with mode: 0644]
src/box_std.rs [new file with mode: 0644]
src/compat.rs [new file with mode: 0644]
src/context.rs [new file with mode: 0644]
src/error/error_impl.rs [new file with mode: 0644]
src/error/error_impl_small.rs [new file with mode: 0644]
src/error/mod.rs [new file with mode: 0644]
src/error_message.rs [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]
src/macros.rs [new file with mode: 0644]
src/result_ext.rs [new file with mode: 0644]
src/small_error.rs [new file with mode: 0644]
src/sync_failure.rs [new file with mode: 0644]
tests/basic_fail.rs [new file with mode: 0644]
tests/fail_compat.rs [new file with mode: 0644]
tests/macro_trailing_comma.rs [new file with mode: 0644]
travis.sh [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..c340151
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "dcd867b0257fa95ae0e393d1a857aa57191af36c"
+  }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1bc55b7
--- /dev/null
@@ -0,0 +1,5 @@
+**/target/
+**/*.rs.bk
+**/Cargo.lock
+public
+book/book
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..a9cbe35
--- /dev/null
@@ -0,0 +1,10 @@
+image: "rust:latest"
+
+pages:
+  script:
+    - sh ./build-docs.sh
+  artifacts:
+    paths:
+      - public
+  only:
+    - master
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..53c70e9
--- /dev/null
@@ -0,0 +1,12 @@
+language: rust
+rust:
+    - 1.31.0
+    - stable
+    - beta
+    - nightly
+cache: cargo
+script:
+  - if [ "$TRAVIS_RUST_VERSION" == "1.31.0" ]; then cp Cargo.lock.ci Cargo.lock; fi
+  - cargo test
+  - cargo test --features backtrace
+  - cargo check --no-default-features
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644 (file)
index 0000000..a2161d0
--- /dev/null
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at boats@mozilla.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/Cargo.lock.ci b/Cargo.lock.ci
new file mode 100644 (file)
index 0000000..1508fa5
--- /dev/null
@@ -0,0 +1,136 @@
+[[package]]
+name = "backtrace"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "failure"
+version = "0.1.6"
+dependencies = [
+ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.6",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.6"
+dependencies = [
+ "failure 0.1.6",
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro2"
+version = "0.4.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "0.15.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
+"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
+"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
+"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
+"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
+"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
+"checksum rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "01b90379b8664dd83460d59bdc5dd1fd3172b8913788db483ed1325171eab2f7"
+"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
+"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..5a5dde0
--- /dev/null
@@ -0,0 +1,35 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "failure"
+version = "0.1.8"
+authors = ["Without Boats <boats@mozilla.com>"]
+description = "Experimental error handling abstraction."
+homepage = "https://rust-lang-nursery.github.io/failure/"
+documentation = "https://docs.rs/failure"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-lang-nursery/failure"
+[dependencies.backtrace]
+version = "0.3.3"
+optional = true
+
+[dependencies.failure_derive]
+version = "0.1.7"
+optional = true
+
+[features]
+default = ["std", "derive"]
+derive = ["failure_derive"]
+std = ["backtrace"]
+[badges.maintenance]
+status = "deprecated"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..038eaff
--- /dev/null
@@ -0,0 +1,30 @@
+[package]
+authors = ["Without Boats <boats@mozilla.com>"]
+description = "Experimental error handling abstraction."
+documentation = "https://docs.rs/failure"
+homepage = "https://rust-lang-nursery.github.io/failure/"
+license = "MIT OR Apache-2.0"
+name = "failure"
+repository = "https://github.com/rust-lang-nursery/failure"
+
+version = "0.1.8"
+[dependencies.failure_derive]
+optional = true
+version = "0.1.7"
+path = "./failure_derive"
+
+[dependencies.backtrace]
+optional = true
+version = "0.3.3"
+
+[workspace]
+members = [".", "failure_derive"]
+
+[badges]
+maintenance = { status = "deprecated" }
+
+[features]
+default = ["std", "derive"]
+#small-error = ["std"]
+std = ["backtrace"]
+derive = ["failure_derive"]
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..16fe87b
--- /dev/null
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644 (file)
index 0000000..31aa793
--- /dev/null
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..6ff7329
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+all: test
+.PHONY: all
+
+test: 
+       @echo TEST DEFAULT FEATURES
+       @cargo test --all
+       @echo TEST WITH BACKTRACE
+       @cargo test --features backtrace --all
+       @echo TEST NO DEFAULT FEATURES
+       @cargo check --no-default-features --all
+.PHONY: test
+
+check:
+       @cargo check --all
+.PHONY: check
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..0def985
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+# failure - a new error management story
+
+**Notice**: `failure` is deprecated. If you liked `failure`'s API, consider using:
+- [Anyhow](https://github.com/dtolnay/anyhow) is a good replacement for `failure::Error`.
+- [thiserror](https://github.com/dtolnay/thiserror) is a good, near drop-in replacement for `#[derive(Fail)]`.
+
+---
+
+[![Build Status](https://travis-ci.org/rust-lang-nursery/failure.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/failure)
+[![Latest Version](https://img.shields.io/crates/v/failure.svg)](https://crates.io/crates/failure)
+[![docs](https://docs.rs/failure/badge.svg)](https://docs.rs/failure)
+
+`failure` is designed to make it easier to manage errors in Rust. It is
+intended to replace error management based on `std::error::Error` with a new
+system based on lessons learned over the past several years, including those
+learned from experience with quick-error and error-chain.
+
+`failure` provides two core components:
+
+* `Fail`: A new trait for custom error types.
+* `Error`: A struct which any type that implements `Fail` can be cast into.
+
+## Evolution
+
+Failure is currently evolving as a library.  First of all there is work going
+on in Rust itself to [fix the error trait](https://github.com/rust-lang/rfcs/pull/2504)
+secondarily the original plan for Failure towards 1.0 is unlikely to happen
+in the current form.
+
+As such the original master branch towards 1.0 of failure was removed and
+master now represents the future iteration steps of 0.1 until it's clear
+what happens in the stdlib.
+
+The original 1.0 branch can be found in [evolution/1.0](https://github.com/rust-lang-nursery/failure/tree/evolution/1.0).
+
+## Example
+
+```rust
+extern crate serde;
+extern crate toml;
+
+#[macro_use] extern crate failure;
+#[macro_use] extern crate serde_derive;
+
+use std::collections::HashMap;
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use failure::Error;
+
+// This is a new error type that you've created. It represents the ways a
+// toolchain could be invalid.
+//
+// The custom derive for Fail derives an impl of both Fail and Display.
+// We don't do any other magic like creating new types.
+#[derive(Debug, Fail)]
+enum ToolchainError {
+    #[fail(display = "invalid toolchain name: {}", name)]
+    InvalidToolchainName {
+        name: String,
+    },
+    #[fail(display = "unknown toolchain version: {}", version)]
+    UnknownToolchainVersion {
+        version: String,
+    }
+}
+
+pub struct ToolchainId {
+    // ... etc
+}
+
+impl FromStr for ToolchainId {
+    type Err = ToolchainError;
+
+    fn from_str(s: &str) -> Result<ToolchainId, ToolchainError> {
+        // ... etc
+    }
+}
+
+pub type Toolchains = HashMap<ToolchainId, PathBuf>;
+
+// This opens a toml file containing associations between ToolchainIds and
+// Paths (the roots of those toolchains).
+//
+// This could encounter an io Error, a toml parsing error, or a ToolchainError,
+// all of them will be thrown into the special Error type
+pub fn read_toolchains(path: PathBuf) -> Result<Toolchains, Error>
+{
+    use std::fs::File;
+    use std::io::Read;
+
+    let mut string = String::new();
+    File::open(path)?.read_to_string(&mut string)?;
+
+    let toml: HashMap<String, PathBuf> = toml::from_str(&string)?;
+
+    let toolchains = toml.iter().map(|(key, path)| {
+        let toolchain_id = key.parse()?;
+        Ok((toolchain_id, path))
+    }).collect::<Result<Toolchains, ToolchainError>>()?;
+
+    Ok(toolchains)
+}
+```
+
+## Requirements
+
+Both failure and failure_derive are intended to compile on all stable versions
+of Rust newer than 1.31.0, as well as the latest beta and the latest nightly.
+If either crate fails to compile on any version newer than 1.31.0, please open
+an issue.
+
+failure is **no_std** compatible, though some aspects of it (primarily the
+`Error` type) will not be available in no_std mode.
+
+## License
+
+failure is licensed under the terms of the MIT License or the Apache License
+2.0, at your choosing.
+
+## Code of Conduct
+
+Contribution to the failure crate is organized under the terms of the
+Contributor Covenant, the maintainer of failure, @withoutboats, promises to
+intervene to uphold that code of conduct.
diff --git a/RELEASES.md b/RELEASES.md
new file mode 100644 (file)
index 0000000..499df4b
--- /dev/null
@@ -0,0 +1,61 @@
+# Version 0.1.6
+
+- Update `syn`, `quote`, and `proc_macro2` dependencies to 1.0.
+- Bump MSRV to 1.31.0.
+
+# Version 0.1.5
+
+- Resolve a regression with error conversions (#290)
+- Added `name()` to `Fail` and `Error`
+
+# Version 0.1.4
+
+- Improved error reporting of the derive feature
+- Resolved a potential internal ambiguity when using the backtrace feature
+  that prevented backtrace from improving an upstream API.
+- Changed the bounds on std error compat conversions through the From trait
+  to take Sync and Send into account.
+
+# Version 0.1.3
+
+- Added `Context::map`
+- Fixed a memory leak for older rust versions on error downcast
+
+# Version 0.1.2
+
+The original plan to release 1.0.0 was changed so that version 0.1.1 is released and a related [RFC to fix the error trait](https://github.com/rust-lang/rfcs/pull/2504) is submitted. See README for details.
+
+- Fix `failure_derive` to work with Rust 2018.
+- Add `#[fail(cause)]` that works similarly with `#[cause]`. The new form is preferred.
+- Fix `"backtrace"` feature to work without `"std"` feature.
+- Add `Compat::get_ref`.
+- Add `Fallible`.
+- Deprecate `Fail::causes` and `<dyn Fail>::causes` in favor of newly added `<dyn Fail>::iter_causes`.
+- Deprecate `Fail::root_cause` and `<dyn Fail>::root_cause` in favor of newly added `<dyn Fail>::find_root_cause`.
+- Add `<dyn Fail>::iter_chain`.
+- Implement `Box<Fail>: Fail`.
+- Add `Error::from_boxed_compat`.
+- Deprecate `Error::cause` in favor of newly added `Error::as_fail`.
+- Deprecate `Error::causes` in favor of newly added `Error::iter_chain`.
+- Deprecate `Error::root_cause` in favor of newly added `Error::find_root_cause`.
+- Add `Error::iter_causes`.
+- Implement `Error: AsRef<Fail>`.
+- Fix `Debug` implementation of `SyncFailure`.
+
+# Version 0.1.1
+
+- Add a `Causes` iterator, which iterates over the causes of a failure. Can be
+  accessed through the `Fail::causes` or `Error::causes` methods.
+- Add the `bail!` macro, which "throws" from the function.
+- Add the `ensure!` macro, which is like an "assert" which throws instead of
+  panicking.
+- The derive now supports a no_std mode.
+- The derive is re-exported from `failure` by default, so that users do not
+  have to directly depend on `failure_derive`.
+- Add a impl of `From<D> for Context<D>`, allowing users to `?` the `D` type to
+  produce a `Context<D>` (for cases where there is no further underlying
+  error).
+
+# Version 0.1.0
+
+- Initial version.
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
new file mode 100644 (file)
index 0000000..e5c8a3b
--- /dev/null
@@ -0,0 +1,14 @@
+# Summary
+
+- [failure](./intro.md)
+- [How to use failure](./howto.md)
+    - [The Fail trait](./fail.md)
+    - [Deriving Fail](./derive-fail.md)
+    - [The Error type](./error.md)
+    - [`bail!` and `ensure!`](./bail-and-ensure.md)
+- [Patterns & Guidance](./guidance.md)
+    - [Strings as errors](./error-msg.md)
+    - [A Custom Fail type](./custom-fail.md)
+    - [Using the Error type](./use-error.md)
+    - [An Error and ErrorKind pair](./error-errorkind.md)
+    - [Strings and custom fail type](./string-custom-error.md)
diff --git a/book/src/bail-and-ensure.md b/book/src/bail-and-ensure.md
new file mode 100644 (file)
index 0000000..1326f0e
--- /dev/null
@@ -0,0 +1,18 @@
+# `bail!` and `ensure!`
+
+If you were a fan of the `bail!` and ensure! macros from error-chain, good news. failure has a version of these macros as well.
+
+The `bail!` macro returns an error immediately, based on a format string. The `ensure!` macro additionally takes a conditional, and returns the error only if that conditional is false. You can think of `bail!` and `ensure!` as being analogous to `panic!` and `assert!`, but throwing errors instead of panicking.
+
+`bail!` and `ensure!` macros are useful when you are prototyping and you want to write your custom errors later. It is also the simplest example of using the failure crate.
+
+## Example
+```rust
+#[macro_use] extern crate failure;
+
+fn safe_cast_to_unsigned(n:i32) -> Result<u32, error::Failure>
+{
+    ensure!(n>=0, "number cannot be smaller than 0!");
+    (u32) n
+}
+```
\ No newline at end of file
diff --git a/book/src/custom-fail.md b/book/src/custom-fail.md
new file mode 100644 (file)
index 0000000..324c041
--- /dev/null
@@ -0,0 +1,75 @@
+# A Custom Fail type
+
+This pattern is a way to define a new kind of failure. Defining a new kind of
+failure can be an effective way of representing an error for which you control
+all of the possible failure cases. It has several advantages:
+
+1. You can enumerate exactly all of the possible failures that can occur in
+this context.
+2. You have total control over the representation of the failure type.
+3. Callers can destructure your error without any sort of downcasting.
+
+To implement this pattern, you should define your own type that implements
+`Fail`. You can use the [custom derive][derive-fail] to make this easier. For
+example:
+
+```rust
+#[derive(Fail, Debug)]
+#[fail(display = "Input was invalid UTF-8")]
+pub struct Utf8Error;
+```
+
+This type can become as large and complicated as is appropriate to your use
+case. It can be an enum with a different variant for each possible error, and
+it can carry data with more precise information about the error. For example:
+
+```rust
+#[derive(Fail, Debug)]
+#[fail(display = "Input was invalid UTF-8 at index {}", index)]
+pub struct Utf8Error {
+    index: usize,
+}
+```
+
+## When might you use this pattern?
+
+If you need to raise an error that doesn't come from one of your dependencies,
+this is a great pattern to use.
+
+You can also use this pattern in conjunction with [using `Error`][use-error] or
+defining an [Error and ErrorKind pair][error-errorkind]. Those functions which
+are "pure logic" and have a very constrained set of errors (such as parsing
+simple formats) might each return a different custom Fail type, and then the
+function which merges them all together, does IO, and so on, would return a
+more complex type like `Error` or your custom Error/ErrorKind.
+
+## Caveats on this pattern
+
+When you have a dependency which returns a different error type, often you will
+be inclined to add it as a variant on your own error type. When you do that,
+you should tag the underlying error as the `#[fail(cause)]` of your error:
+
+```rust
+#[derive(Fail, Debug)]
+pub enum MyError {
+    #[fail(display = "Input was invalid UTF-8 at index {}", _0)]
+    Utf8Error(usize),
+    #[fail(display = "{}", _0)]
+    Io(#[fail(cause)] io::Error),
+}
+```
+
+Up to a limit, this design can work. However, it has some problems:
+
+- It can be hard to be forward compatible with new dependencies that raise
+  their own kinds of errors in the future.
+- It defines a 1-1 relationship between a variant of the error and an
+  underlying error.
+
+Depending on your use case, as your function grows in complexity, it can be
+better to transition to [using Error][use-error] or [defining an Error &
+ErrorKind pair][error-errorkind].
+
+[derive-fail]: ./derive-fail.html
+[use-error]: ./use-error.html
+[error-errorkind]: ./error-errorkind.html
diff --git a/book/src/derive-fail.md b/book/src/derive-fail.md
new file mode 100644 (file)
index 0000000..6fffd99
--- /dev/null
@@ -0,0 +1,177 @@
+# Deriving `Fail`
+
+Though you can implement `Fail` yourself, we also provide a derive macro to
+generate the impl for you. To get access to this macro, you must tag the extern
+crate declaration with `#[macro_use]`, as in:
+
+```rust
+#[macro_use] extern crate failure;
+```
+
+In its smallest form, deriving Fail looks like this:
+
+```rust
+#[macro_use] extern crate failure;
+
+use std::fmt;
+
+#[derive(Fail, Debug)]
+struct MyError;
+
+impl fmt::Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "An error occurred.")
+    }
+}
+```
+
+All failures need to implement `Display`, so we have added an impl of
+Display. However, implementing `Display` is much more boilerplate than
+implementing `Fail` - this is why we support deriving `Display` for you.
+
+## Deriving `Display`
+
+You can derive an implementation of `Display` with a special attribute:
+
+```rust
+#[macro_use] extern crate failure;
+
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred.")]
+struct MyError;
+```
+
+This attribute will cause the `Fail` derive to also generate an impl of
+`Display`, so that you don't have to implement one yourself.
+
+### String interpolation
+
+String literals are not enough for error messages in many cases. Often, you
+want to include parts of the error value interpolated into the message. You can
+do this with failure using the same string interpolation syntax as Rust's
+formatting and printing macros:
+
+```rust
+#[macro_use] extern crate failure;
+
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred with error code {}. ({})", code, message)]
+struct MyError {
+    code: i32,
+    message: String,
+}
+```
+
+Note that unlike code that would appear in a method, this does not use
+something like `self.code` or `self.message`; it just uses the field names
+directly. This is because of a limitation in Rust's current attribute syntax.
+As a result, you can only interpolate fields through the derivation; you cannot
+perform method calls or use other arbitrary expressions.
+
+### Tuple structs
+
+With regular structs, you can use the name of the field in string
+interpolation. When deriving Fail for a tuple struct, you might expect to use
+the numeric index to refer to fields `0`, `1`, et cetera. However, a compiler
+limitation prevents this from parsing today.
+
+For the time being, tuple field accesses in the display attribute need to be
+prefixed with an underscore:
+
+```rust
+#[macro_use] extern crate failure;
+
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred with error code {}.", _0)]
+struct MyError(i32);
+
+
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred with error code {} ({}).", _0, _1)]
+struct MyOtherError(i32, String);
+```
+
+### Enums
+
+Implementing Display is also supported for enums by applying the attribute to
+each variant of the enum, rather than to the enum as a whole. The Display impl
+will match over the enum to generate the correct error message. For example:
+
+```rust
+#[macro_use] extern crate failure;
+
+#[derive(Fail, Debug)]
+enum MyError {
+    #[fail(display = "{} is not a valid version.", _0)]
+    InvalidVersion(u32),
+    #[fail(display = "IO error: {}", error)]
+    IoError { error: io::Error },
+    #[fail(display = "An unknown error has occurred.")]
+    UnknownError,
+}
+```
+
+## Overriding `backtrace`
+
+The backtrace method will be automatically overridden if the type contains a
+field with the type `Backtrace`. This works for both structs and enums.
+
+```rust
+#[macro_use] extern crate failure;
+
+use failure::Backtrace;
+
+/// MyError::backtrace will return a reference to the backtrace field
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred.")]
+struct MyError {
+    backtrace: Backtrace,
+}
+
+/// MyEnumError::backtrace will return a reference to the backtrace only if it
+/// is Variant2, otherwise it will return None.
+#[derive(Fail, Debug)]
+enum MyEnumError {
+    #[fail(display = "An error occurred.")]
+    Variant1,
+    #[fail(display = "A different error occurred.")]
+    Variant2(Backtrace),
+}
+```
+
+This happens automatically; no other annotations are necessary. It only works
+if the type is named Backtrace, and not if you have created an alias for the
+Backtrace type.
+
+## Overriding `cause`
+
+In contrast to `backtrace`, the cause cannot be determined by type name alone
+because it could be any type which implements `Fail`. For this reason, if your
+error has an underlying cause field, you need to annotate that field with
+the `#[fail(cause)]` attribute.
+
+This can be used in fields of enums as well as structs.
+
+
+```rust
+#[macro_use] extern crate failure;
+
+use std::io;
+
+/// MyError::cause will return a reference to the io_error field
+#[derive(Fail, Debug)]
+#[fail(display = "An error occurred.")]
+struct MyError {
+    #[fail(cause)] io_error: io::Error,
+}
+
+/// MyEnumError::cause will return a reference only if it is Variant2,
+/// otherwise it will return None.
+#[derive(Fail, Debug)]
+enum MyEnumError {
+    #[fail(display = "An error occurred.")]
+    Variant1,
+    #[fail(display = "A different error occurred.")]
+    Variant2(#[fail(cause)] io::Error),
+}
+```
diff --git a/book/src/error-errorkind.md b/book/src/error-errorkind.md
new file mode 100644 (file)
index 0000000..4f1cc4c
--- /dev/null
@@ -0,0 +1,147 @@
+# An Error and ErrorKind pair
+
+This pattern is the most robust way to manage errors - and also the most high
+maintenance. It combines some of the advantages of the [using Error][use-error]
+pattern and the [custom failure][custom-fail] patterns, while avoiding some of
+the disadvantages each of those patterns has:
+
+1. Like `Error`, this is forward compatible with new underlying kinds of
+errors from your dependencies.
+2. Like custom failures, this pattern allows you to specify additional information about the error that your dependencies don't give you.
+3. Like `Error`, it can be easier to convert underlying errors from dependency
+into this type than for custom failures.
+4. Like custom failures, users can gain some information about the error
+without downcasting.
+
+The pattern is to create two new failure types: an `Error` and an `ErrorKind`,
+and to leverage [the `Context` type][context-api] provided by failure.
+
+```rust
+#[derive(Debug)]
+struct MyError {
+    inner: Context<MyErrorKind>,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
+enum MyErrorKind {
+    // A plain enum with no data in any of its variants
+    //
+    // For example:
+    #[fail(display = "A contextual error message.")]
+    OneVariant,
+    // ...
+}
+```
+
+Unfortunately, it is not easy to correctly derive `Fail` for `MyError` so that
+it delegates things to its inner `Context`. You should write those impls
+yourself:
+
+```rust
+impl Fail for MyError {
+    fn name(&self) -> Option<&str> {
+        self.inner.name()
+    }
+
+    fn cause(&self) -> Option<&Fail> {
+        self.inner.cause()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        self.inner.backtrace()
+    }
+}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.inner, f)
+    }
+}
+```
+
+You should also provide some conversions and accessors, to go between a
+Context, your ErrorKind, and your Error:
+
+```rust
+impl MyError {
+    pub fn kind(&self) -> MyErrorKind {
+        *self.inner.get_context()
+    }
+}
+
+impl From<MyErrorKind> for MyError {
+    fn from(kind: MyErrorKind) -> MyError {
+        MyError { inner: Context::new(kind) }
+    }
+}
+
+impl From<Context<MyErrorKind>> for MyError {
+    fn from(inner: Context<MyErrorKind>) -> MyError {
+        MyError { inner: inner }
+    }
+}
+```
+
+With this code set up, you can use the context method from failure to apply
+your ErrorKind to `Result`s in underlying libraries:
+
+```rust
+use failure::ResultExt;
+perform_some_io().context(ErrorKind::NetworkFailure)?;
+```
+
+You can also directly throw `ErrorKind` without an underlying error when
+appropriate:
+
+```rust
+Err(ErrorKind::DomainSpecificError)?
+```
+
+### What should your ErrorKind contain?
+
+Your error kind probably should not carry data - and if it does, it should only
+carry stateless data types that provide additional information about what the
+`ErrorKind` means. This way, your `ErrorKind` can be `Eq`, making it
+easy to use as a way of comparing errors.
+
+Your ErrorKind is a way of providing information about what errors mean
+appropriate to the level of abstraction that your library operates at. As some
+examples:
+
+- If your library expects to read from the user's `Cargo.toml`, you might have
+  a `InvalidCargoToml` variant, to capture what `io::Error` and `toml::Error`
+  mean in the context of your library.
+- If your library does both file system activity and network activity, you
+  might have `Filesystem` and `Network` variants, to divide up the `io::Error`s
+  between which system in particular failed.
+
+Exactly what semantic information is appropriate depends entirely on what this
+bit of code is intended to do.
+
+## When might you use this pattern?
+
+The most likely use cases for this pattern are mid-layer which perform a
+function that requires many dependencies, and that are intended to be used in
+production. Libraries with few dependencies do not need to manage many
+underlying error types and can probably suffice with a simpler [custom
+failure][custom-fail]. Applications that know they are almost always just going
+to log these errors can get away with [using the Error type][use-error] rather
+than managing extra context information.
+
+That said, when you need to provide the most expressive information about an
+error possible, this can be a good approach.
+
+## Caveats on this pattern
+
+This pattern is the most involved pattern documented in this book. It involves
+a lot of boilerplate to set up (which may be automated away eventually), and it
+requires you to apply a contextual message to every underlying error that is
+thrown inside your code. It can be a lot of work to maintain this pattern.
+
+Additionally, like the Error type, the Context type may use an allocation and a
+dynamic dispatch internally. If you know this is too expensive for your use
+case, you should not use this pattern.
+
+[use-error]: ./use-error.html
+[custom-fail]: ./custom-fail.html
+[context-api]: https://docs.rs/failure/latest/failure/struct.Context.html
diff --git a/book/src/error-msg.md b/book/src/error-msg.md
new file mode 100644 (file)
index 0000000..61bde14
--- /dev/null
@@ -0,0 +1,59 @@
+# Strings as errors
+
+This pattern is a way to create new errors without doing much set up. It is
+definitely the sloppiest way to throw errors. It can be great to use this
+during prototyping, but maybe not in the final product.
+
+String types do not implement `Fail`, which is why there are two adapters to
+create failures from a string:
+
+- [`failure::err_msg`][err-msg-api] - a function that takes a displayable
+  type and creates a failure from it. This can take a String or a string
+  literal.
+- [`format_err!`][format-err-api] - a macro with string interpolation, similar
+  to `format!` or `println!`.
+
+```rust
+fn check_range(x: usize, range: Range<usize>) -> Result<usize, Error> {
+    if x < range.start {
+        return Err(format_err!("{} is below {}", x, range.start));
+    }
+    if x >= range.end {
+        return Err(format_err!("{} is above {}", x, range.end));
+    }
+    Ok(x)
+}
+```
+
+If you're going to use strings as errors, we recommend [using
+`Error`][use-error] as your error type, rather than `ErrorMessage`; this way,
+if some of your strings are `String` and some are `&'static str`, you don't
+need worry about merging them into a single string type.
+
+## When might you use this pattern?
+
+This pattern is the easiest to set up and get going with, so it can be great
+when prototyping or spiking out an early design. It can also be great when you
+know that an error variant is extremely uncommon, and that there is really no
+way to handle it other than to log the error and move on.
+
+## Caveats on this pattern
+
+If you are writing a library you plan to publish to crates.io, this is probably
+not a good way to handle errors, because it doesn't give your clients very much
+control. For public, open source libraries, we'd recommend using [custom
+failures][custom-fail] in the cases where you would use a string as an error.
+
+This pattern can also be very brittle. If you ever want to branch over which
+error was returned, you would have to match on the exact contents of the
+string. If you ever change the string contents, that will silently break that
+match.
+
+For these reasons, we strongly recommend against using this pattern except for
+prototyping and when you know the error is just going to get logged or reported
+to the users.
+
+[custom-fail]: ./custom-fail.html
+[use-error]: ./use-error.html
+[err-msg-api]: https://docs.rs/failure/latest/failure/fn.err_msg.html
+[format-err-api]: https://docs.rs/failure/latest/failure/macro.format_err.html
diff --git a/book/src/error.md b/book/src/error.md
new file mode 100644 (file)
index 0000000..f37e4c3
--- /dev/null
@@ -0,0 +1,100 @@
+# The `Error` type
+
+In addition to the trait `Fail`, failure provides a type called `Error`. Any
+type that implements `Fail` can be cast into `Error` using From and Into, which
+allows users to throw errors using `?` which have different types, if the
+function returns an `Error`.
+
+For example:
+
+```rust
+// Something you can deserialize
+#[derive(Deserialize)]
+struct Object {
+    ...
+}
+
+impl Object {
+    // This throws both IO Errors and JSON Errors, but they both get converted
+    // into the Error type.
+    fn from_file(path: &Path) -> Result<Object, Error> {
+        let mut string = String::new();
+        File::open(path)?.read_to_string(&mut string)?;
+        let object = json::from_str(&string)?;
+        Ok(object)
+    }
+}
+```
+
+## Causes and Backtraces
+
+The Error type has all of the methods from the Fail trait, with a few notable
+differences. Most importantly, the cause and backtrace methods on Error do not
+return Options - an Error is *guaranteed* to have a cause and a backtrace.
+
+```rust
+// Both methods are guaranteed to return an &Fail and an &Backtrace
+println!("{}, {}", error.cause(), error.backtrace())
+```
+
+An `Error`'s cause is always the failure that was cast into this `Error`.
+That failure may have further underlying causes. Unlike Fail, this means that
+the cause of an Error will have the same Display representation as the Error
+itself.
+
+As to the error's guaranteed backtrace, when the conversion into the Error type
+happens, if the underlying failure does not provide a backtrace, a new
+backtrace is constructed pointing to that conversion point (rather than the
+origin of the error). This construction only happens if there is no underlying
+backtrace; if it does have a backtrace no new backtrace is constructed.
+
+## Downcasting
+
+The Error type also supports downcasting into any concrete Fail type. It can be
+downcast by reference or by value - when downcasting by value, the return type
+is `Result<T, Error>`, allowing you to get the error back out of it.
+
+```rust
+match error.downcast::<io::Error>() {
+    Ok(io_error)    => { ... }
+    Err(error)      => { ... }
+}
+```
+
+## Implementation details
+
+`Error` is essentially a trait object, but with some fanciness it may generate
+and store the backtrace if the underlying failure did not have one. In
+particular, we use a custom dynamically sized type to store the backtrace
+information inline with the trait object data.
+
+```rust
+struct Error {
+    // Inner<Fail> is a dynamically sized type
+    inner: Box<Inner<Fail>>,
+}
+
+struct Inner<F: Fail> {
+    backtrace: Backtrace,
+    failure: F,
+}
+```
+
+By storing the backtrace in the heap this way, we avoid increasing the size of
+the Error type beyond that of two non-nullable pointers. This keeps the size of
+the `Result` type from getting too large, avoiding having a negative impact on
+the "happy path" of returning Ok. For example, a `Result<(), Error>` should be
+represented as a pair of nullable pointers, with the null case representing
+`Ok`. Similar optimizations can be applied to values up to at least a pointer
+in size.
+
+To emphasize: Error is intended for use cases where the error case is
+considered relatively uncommon. This optimization makes the overhead of an
+error less than it otherwise would be for the Ok branch. In cases where errors
+are going to be returned extremely frequently, returning this Error type is
+probably not appropriate, but you should benchmark in those cases.
+
+(As a rule of thumb: if you're not sure if you can afford to have a trait
+object, you probably *can* afford it. Heap allocations are not nearly as cheap
+as stack allocations, but they're cheap enough that you can almost always
+afford them.)
diff --git a/book/src/fail.md b/book/src/fail.md
new file mode 100644 (file)
index 0000000..720b52e
--- /dev/null
@@ -0,0 +1,152 @@
+# The `Fail` trait
+
+The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has
+been designed to support a number of operations:
+
+- Because it is bound by both `Debug` and `Display`, any failure can be
+  printed in two ways.
+- It has both a `backtrace` and a `cause` method, allowing users to get
+  information about how the error occurred.
+- It supports wrapping failures in additional contextual information.
+- Because it is bound by `Send` and `Sync`, failures can be moved and shared
+  between threads easily.
+- Because it is bound by `'static`, the abstract `Fail` trait object can be
+  downcast into concrete types.
+
+Every new error type in your code should implement `Fail`, so it can be
+integrated into the entire system built around this trait. You can manually
+implement `Fail` yourself, or you can use the derive for `Fail` defined
+in a separate crate and documented [here][derive-docs].
+
+Implementors of this trait are called 'failures'.
+
+## Cause
+
+Often, an error type contains (or could contain) another underlying error type
+which represents the "cause" of this error - for example, if your custom error
+contains an `io::Error`, that is the cause of your error.
+
+The cause method on the `Fail` trait allows all errors to expose their underlying
+cause - if they have one - in a consistent way. Users can loop over the chain
+of causes, for example, getting the entire series of causes for an error:
+
+```rust
+// Assume err is a type that implements `Fail`
+let mut fail: &Fail = err;
+
+while let Some(cause) = fail.cause() {
+    println!("{}", cause);
+
+    // Make `fail` the reference to the cause of the previous fail, making the
+    // loop "dig deeper" into the cause chain.
+    fail = cause;
+}
+```
+
+Because `&Fail` supports downcasting, you can also inspect causes in more
+detail if you are expecting a certain failure:
+
+```rust
+while let Some(cause) = fail.cause() {
+
+    if let Some(err) = cause.downcast_ref::<io::Error>() {
+        // treat io::Error specially
+    } else {
+        // fallback case
+    }
+
+    fail = cause;
+}
+```
+
+For convenience an iterator is also provided:
+
+```rust
+// Assume err is a type that implements `Fail`
+let mut fail: &Fail = err;
+
+for cause in fail.iter_causes() {
+    println!("{}", cause);
+}
+```
+
+## Backtraces
+
+Errors can also generate a backtrace when they are constructed, helping you
+determine the place the error was generated and the function chain that called into
+that. Like causes, this is entirely optional - the authors of each failure
+have to decide if generating a backtrace is appropriate in their use case.
+
+The backtrace method allows all errors to expose their backtrace if they have
+one. This enables a consistent method for getting the backtrace from an error:
+
+```rust
+// We don't even know the type of the cause, but we can still get its
+// backtrace.
+if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) {
+    println!("{}", bt)
+}
+```
+
+The `Backtrace` type exposed by `failure` is different from the `Backtrace` exposed
+by the [backtrace crate][backtrace-crate], in that it has several optimizations:
+
+- It has a `no_std` compatible form which will never be generated (because
+  backtraces require heap allocation), and should be entirely compiled out.
+- It will not be generated unless the `RUST_BACKTRACE` environment variable has
+  been set at runtime.
+- Symbol resolution is delayed until the backtrace is actually printed, because
+  this is the most expensive part of generating a backtrace.
+
+## Context
+
+Often, the libraries you are using will present error messages that don't
+provide very helpful information about what exactly has gone wrong. For
+example, if an `io::Error` says that an entity was "Not Found," that doesn't
+communicate much about what specific file was missing - if it even was a file
+(as opposed to a directory for example).
+
+You can inject additional context to be carried with this error value,
+providing semantic information about the nature of the error appropriate to the
+level of abstraction that the code you are writing operates at. The `context`
+method on `Fail` takes any displayable value (such as a string) to act as
+context for this error.
+
+Using the `ResultExt` trait, you can also get `context` as a convenient method on
+`Result` directly. For example, suppose that your code attempted to read from a
+Cargo.toml. You can wrap the `io::Error`s that occur with additional context
+about what operation has failed:
+
+```rust
+use failure::ResultExt;
+
+let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?;
+file.read_to_end(&buffer).context("Could not read Cargo.toml")?;
+```
+
+The `Context` object also has a constructor that does not take an underlying
+error, allowing you to create ad hoc Context errors alongside those created by
+applying the `context` method to an underlying error.
+
+## Backwards compatibility
+
+We've taken several steps to make transitioning from `std::error` to `failure` as
+painless as possible.
+
+First, there is a blanket implementation of `Fail` for all types that implement
+`std::error::Error`, as long as they are `Send + Sync + 'static`. If you are
+dealing with a library that hasn't shifted to `Fail`, it is automatically
+compatible with `failure` already.
+
+Second, `Fail` contains a method called `compat`, which produces a type that
+implements `std::error::Error`. If you have a type that implements `Fail`, but
+not the older `Error` trait, you can call `compat` to get a type that does
+implement that trait (for example, if you need to return a `Box<Error>`).
+
+The biggest hole in our backwards compatibility story is that you cannot
+implement `std::error::Error` and also override the backtrace and cause methods
+on `Fail`. We intend to enable this with specialization when it becomes stable.
+
+[derive-docs]: ./derive-fail.html
+[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html
+[backtrace-crate]: http://alexcrichton.com/backtrace-rs
diff --git a/book/src/guidance.md b/book/src/guidance.md
new file mode 100644 (file)
index 0000000..7023ca4
--- /dev/null
@@ -0,0 +1,24 @@
+# Patterns & Guidance
+
+failure is not a "one size fits all" approach to error management. There are
+multiple patterns that emerge from the API this library provides, and users
+need to determine which pattern makes sense for them. This section documents
+some patterns and how users might use them.
+
+In brief, these are the patterns documented here:
+
+- **[Strings as errors](./error-msg.md):** Using strings as your error
+  type. Good for prototyping.
+- **[A Custom Fail type](./custom-fail.md):** Defining a custom type to be
+  your error type. Good for APIs where you control all or more of the
+  possible failures.
+- **[Using the Error type](./use-error.md):** Using the Error type to pull
+  together multiple failures of different types. Good for applications and
+  APIs that know the error won't be inspected much more.
+- **[An Error and ErrorKind pair](./error-errorkind.md):** Using both a
+  custom error type and an ErrorKind enum to create a very robust error
+  type. Good for public APIs in large crates.
+
+(Though each of these items identifies a use case which this pattern would be
+good for, in truth each of them can be applied in various contexts. Its up to
+you to decide what makes the most sense for your particular use case.)
diff --git a/book/src/howto.md b/book/src/howto.md
new file mode 100644 (file)
index 0000000..5c8135b
--- /dev/null
@@ -0,0 +1,8 @@
+# How to use failure
+
+This section of the documentation is about how the APIs exposed in failure can
+be used. It is organized around the major APIs of failure:
+
+- **[The Fail trait](./fail.md):** The primary abstraction provided by failure.
+- **[Deriving Fail](./derive-fail.md):** A custom derive for the Fail trait.
+- **[The Error type](./error.md):** A convenient wrapper around any Fail type.
diff --git a/book/src/intro.md b/book/src/intro.md
new file mode 100644 (file)
index 0000000..318477a
--- /dev/null
@@ -0,0 +1,77 @@
+# failure
+
+This is the documentation for the failure crate, which provides a system for
+creating and managing errors in Rust. Additional documentation is found here:
+
+* [API documentation][api]
+* [failure source code][repo]
+
+[api]: https://docs.rs/failure
+[repo]: https://github.com/rust-lang-nursery/failure
+
+```rust
+extern crate serde;
+extern crate toml;
+
+#[macro_use] extern crate failure;
+#[macro_use] extern crate serde_derive;
+
+use std::collections::HashMap;
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use failure::Error;
+
+// This is a new error type that you've created. It represents the ways a
+// toolchain could be invalid.
+//
+// The custom derive for Fail derives an impl of both Fail and Display.
+// We don't do any other magic like creating new types.
+#[derive(Debug, Fail)]
+enum ToolchainError {
+    #[fail(display = "invalid toolchain name: {}", name)]
+    InvalidToolchainName {
+        name: String,
+    },
+    #[fail(display = "unknown toolchain version: {}", version)]
+    UnknownToolchainVersion {
+        version: String,
+    }
+}
+
+pub struct ToolchainId {
+    // ... etc
+}
+
+impl FromStr for ToolchainId {
+    type Err = ToolchainError;
+
+    fn from_str(s: &str) -> Result<ToolchainId, ToolchainError> {
+        // ... etc
+    }
+}
+
+pub type Toolchains = HashMap<ToolchainId, PathBuf>;
+
+// This opens a toml file containing associations between ToolchainIds and
+// Paths (the roots of those toolchains).
+//
+// This could encounter an io Error, a toml parsing error, or a ToolchainError,
+// all of them will be thrown into the special Error type
+pub fn read_toolchains(path: PathBuf) -> Result<Toolchains, Error>
+{
+    use std::fs::File;
+    use std::io::Read;
+
+    let mut string = String::new();
+    File::open(path)?.read_to_string(&mut string)?;
+
+    let toml: HashMap<String, PathBuf> = toml::from_str(&string)?;
+
+    let toolchains = toml.iter().map(|(key, path)| {
+        let toolchain_id = key.parse()?;
+        Ok((toolchain_id, path))
+    }).collect::<Result<Toolchains, ToolchainError>>()?;
+
+    Ok(toolchains)
+}
diff --git a/book/src/string-custom-error.md b/book/src/string-custom-error.md
new file mode 100644 (file)
index 0000000..5ea7b8f
--- /dev/null
@@ -0,0 +1,168 @@
+# Strings and custom fail type
+
+This pattern is an hybrid between the [_An Error and ErrorKind pair_](./error-errorkind.md) and
+[_Using the Error type_](./use-error.md).
+
+Such an error type can be implemented in the same way that what was shown in
+the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern, but here, the context is a
+simple string:
+
+```rust
+extern crate core;
+extern crate failure;
+
+use core::fmt::{self, Display};
+use failure::{Backtrace, Context, Fail, ResultExt};
+
+#[derive(Debug)]
+pub struct MyError {
+    inner: Context<String>,
+}
+
+impl Fail for MyError {
+    fn name(&self) -> Option<&str> {
+        self.inner.name()
+    }
+
+    fn cause(&self) -> Option<&Fail> {
+        self.inner.cause()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        self.inner.backtrace()
+    }
+}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.inner, f)
+    }
+}
+```
+
+To make the type easier to use, a few impls can be added:
+
+```rust
+// Allows writing `MyError::from("oops"))?`
+impl From<&'static str> for MyError {
+    fn from(msg: &'static str) -> MyError {
+        MyError {
+            inner: Context::new(msg),
+        }
+    }
+}
+
+// Allows adding more context via a String
+impl From<Context<String>> for MyError {
+    fn from(inner: Context<String>) -> MyError {
+        MyError { inner }
+    }
+}
+
+// Allows adding more context via a &str
+impl From<Context<&'static str>> for MyError {
+    fn from(inner: Context<&'static str>) -> MyError {
+        MyError {
+            inner: inner.map(|s| s.to_string()),
+        }
+    }
+}
+```
+
+Here is how it is used:
+
+```rust
+fn main() {
+    println!("{:?}", err2());
+}
+
+// Unlike the "Using the Error type" pattern, functions return our own error
+// type here.
+fn err1() -> Result<(), MyError> {
+    Ok(Err(MyError::from("err1"))?)
+}
+
+fn err2() -> Result<(), MyError> {
+    // Unlike the "An Error and ErrorKind pair" pattern, our context is a
+    // simple string. We can chain errors and provide detailed error messages,
+    // but we don't have to deal with the complexity of an error kind type
+    Ok(err1().context("err2")?)
+}
+```
+
+## Variant with `&'static str`
+
+If you don't need to format strings, you can avoid an
+allocation by using a `Context<&'static str>` instead of a
+`Context<String>`.
+
+```rust
+extern crate core;
+extern crate failure;
+
+use core::fmt::{self, Display};
+use failure::{Backtrace, Context, Fail, ResultExt};
+
+#[derive(Debug)]
+pub struct MyError {
+    inner: Context<&'static str>,
+}
+
+impl Fail for MyError {
+    fn name(&self) -> Option<&str> {
+        self.inner.name()
+    }
+
+    fn cause(&self) -> Option<&Fail> {
+        self.inner.cause()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        self.inner.backtrace()
+    }
+}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.inner, f)
+    }
+}
+
+impl From<&'static str> for MyError {
+    fn from(msg: &'static str) -> MyError {
+        MyError {
+            inner: Context::new(msg.into()),
+        }
+    }
+}
+
+impl From<Context<&'static str>> for MyError {
+    fn from(inner: Context<&'static str>) -> MyError {
+        MyError {
+            inner,
+        }
+    }
+}
+```
+
+## When might you use this pattern?
+
+Sometimes, you don't want to use the [_Using the Error type_](./use-error.md)
+pattern, because you want to expose a few different error types. But you don't
+want to use the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern
+either, because there is no need to provide the context as an enum or because
+it would be too much work, if the error can occur in many different contexts.
+
+For instance, if you're writing a library that decodes/encodes a complex binary
+format, you might want to expose a `DecodeError` and an `EncodeError` error
+type, but provide the context as a simple string instead of an error kind, because:
+
+- users may not care too much about the context in which a `DecodeError` or
+  `EncodeError` was encountered, they just want a nice message to explain it
+- your binary format is really complex, errors can occur in many different
+  places, and you don't want to end up with a giant `ErrorKind` enum
+
+
+## Caveats on this pattern
+
+If using the `Context<String>` variant, an extra allocation is used for the string.
diff --git a/book/src/use-error.md b/book/src/use-error.md
new file mode 100644 (file)
index 0000000..a0a2944
--- /dev/null
@@ -0,0 +1,66 @@
+# Use the `Error` type
+
+This pattern is a way to manage errors when you have multiple kinds of failure
+that could occur during a single function. It has several distinct advantages:
+
+1. You can start using it without defining any of your own failure types.
+2. All types that implement `Fail` can be thrown into the `Error` type using
+the `?` operator.
+3. As you start adding new dependencies with their own failure types, you can
+start throwing them without making a breaking change.
+
+To use this pattern, all you need to do is return `Result<_, Error>` from your
+functions:
+
+```rust
+use std::io;
+use std::io::BufRead;
+
+use failure::Error;
+use failure::err_msg;
+
+fn my_function() -> Result<(), Error> {
+    let stdin = io::stdin();
+
+    for line in stdin.lock().lines() {
+        let line = line?;
+
+        if line.chars().all(|c| c.is_whitespace()) {
+            break
+        }
+
+        if !line.starts_with("$") {
+            return Err(format_err!("Input did not begin with `$`"));
+        }
+
+        println!("{}", &line[1..]);
+    }
+
+    Ok(())
+}
+```
+
+## When might you use this pattern?
+
+This pattern is very effective when you know you will usually not need to
+destructure the error this function returns. For example:
+
+- When prototyping.
+- When you know you are going to log this error, or display it to the user,
+  either all of the time or nearly all of the time.
+- When it would be impractical for this API to report more custom context for
+  the error (e.g. because it is a trait that doesn't want to add a new Error
+  associated type).
+
+## Caveats on this pattern
+
+There are two primary downsides to this pattern:
+
+- The `Error` type allocates. There are cases where this would be too
+  expensive. In those cases you should use a [custom failure][custom-fail].
+- You cannot recover more information about this error without downcasting. If
+  your API needs to express more contextual information about the error, use
+  the [Error and ErrorKind][error-errorkind] pattern.
+
+[custom-fail]: ./custom-fail.html
+[error-errorkind]: ./error-errorkind.html
diff --git a/build-docs.sh b/build-docs.sh
new file mode 100755 (executable)
index 0000000..fe2039f
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+mkdir public
+cargo doc --no-deps
+cargo install mdbook --no-default-features
+mdbook build ./book
+cp -r ./target/doc/ ./public
+cp -r ./book/book/* ./public
+find $PWD/public | grep "\.html\$"
diff --git a/examples/bail_ensure.rs b/examples/bail_ensure.rs
new file mode 100644 (file)
index 0000000..05c399b
--- /dev/null
@@ -0,0 +1,26 @@
+#[macro_use]
+extern crate failure;
+
+use failure::Error;
+
+fn bailer() -> Result<(), Error> {
+    // bail!("ruh roh");
+    bail!("ruh {}", "roh");
+}
+
+fn ensures() -> Result<(), Error> {
+    ensure!(true, "true is false");
+    ensure!(false, "false is false");
+    Ok(())
+}
+
+fn main() {
+    match bailer() {
+        Ok(_) => println!("ok"),
+        Err(e) => println!("{}", e),
+    }
+    match ensures() {
+        Ok(_) => println!("ok"),
+        Err(e) => println!("{}", e),
+    }
+}
diff --git a/examples/error_as_cause.rs b/examples/error_as_cause.rs
new file mode 100644 (file)
index 0000000..24e5b06
--- /dev/null
@@ -0,0 +1,18 @@
+#[macro_use]
+extern crate failure;
+
+use failure::{err_msg, Error, Fail};
+
+#[derive(Debug, Fail)]
+#[fail(display = "my wrapping error")]
+struct WrappingError(#[fail(cause)] Error);
+
+fn bad_function() -> Result<(), WrappingError> {
+    Err(WrappingError(err_msg("this went bad")))
+}
+
+fn main() {
+    for cause in Fail::iter_causes(&bad_function().unwrap_err()) {
+        println!("{}", cause);
+    }
+}
diff --git a/examples/simple.rs b/examples/simple.rs
new file mode 100644 (file)
index 0000000..fc39601
--- /dev/null
@@ -0,0 +1,22 @@
+#[macro_use]
+extern crate failure;
+
+use failure::Fail;
+
+#[derive(Debug, Fail)]
+#[fail(display = "my error")]
+struct MyError;
+
+#[derive(Debug, Fail)]
+#[fail(display = "my wrapping error")]
+struct WrappingError(#[fail(cause)] MyError);
+
+fn bad_function() -> Result<(), WrappingError> {
+    Err(WrappingError(MyError))
+}
+
+fn main() {
+    for cause in Fail::iter_chain(&bad_function().unwrap_err()) {
+        println!("{}: {}", cause.name().unwrap_or("Error"), cause);
+    }
+}
diff --git a/examples/string_custom_error_pattern.rs b/examples/string_custom_error_pattern.rs
new file mode 100644 (file)
index 0000000..72cf651
--- /dev/null
@@ -0,0 +1,76 @@
+//! This example show the pattern "Strings and custom fail type" described in the book
+extern crate core;
+extern crate failure;
+
+use core::fmt::{self, Display};
+use failure::{Backtrace, Context, Fail, ResultExt};
+
+fn main() {
+    let err = err1().unwrap_err();
+    // Print the error itself
+    println!("error: {}", err);
+    // Print the chain of errors that caused it
+    for cause in Fail::iter_causes(&err) {
+        println!("caused by: {}", cause);
+    }
+}
+
+fn err1() -> Result<(), MyError> {
+    // The context can be a String
+    Ok(err2().context("err1".to_string())?)
+}
+
+fn err2() -> Result<(), MyError> {
+    // The context can be a &'static str
+    Ok(err3().context("err2")?)
+}
+
+fn err3() -> Result<(), MyError> {
+    Ok(Err(MyError::from("err3"))?)
+}
+
+#[derive(Debug)]
+pub struct MyError {
+    inner: Context<String>,
+}
+
+impl Fail for MyError {
+    fn cause(&self) -> Option<&Fail> {
+        self.inner.cause()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        self.inner.backtrace()
+    }
+}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.inner, f)
+    }
+}
+
+// Allows writing `MyError::from("oops"))?`
+impl From<&'static str> for MyError {
+    fn from(msg: &'static str) -> MyError {
+        MyError {
+            inner: Context::new(msg.into()),
+        }
+    }
+}
+
+// Allows adding more context via a String
+impl From<Context<String>> for MyError {
+    fn from(inner: Context<String>) -> MyError {
+        MyError { inner }
+    }
+}
+
+// Allows adding more context via a &str
+impl From<Context<&'static str>> for MyError {
+    fn from(inner: Context<&'static str>) -> MyError {
+        MyError {
+            inner: inner.map(|s| s.to_string()),
+        }
+    }
+}
diff --git a/src/as_fail.rs b/src/as_fail.rs
new file mode 100644 (file)
index 0000000..6e4172b
--- /dev/null
@@ -0,0 +1,37 @@
+use Fail;
+
+/// The `AsFail` trait
+///
+/// This trait is similar to `AsRef<Fail>`, but it is specialized to handle
+/// the dynamic object of `Fail`. Implementors of `Fail` have a blanket
+/// implementation. It is used in `failure_derive` in order to generate a
+/// custom cause.
+pub trait AsFail {
+    /// Converts a reference to `Self` into a dynamic trait object of `Fail`.
+    fn as_fail(&self) -> &dyn Fail;
+}
+
+impl<T> AsFail for T
+where
+    T: Fail,
+{
+    fn as_fail(&self) -> &dyn Fail {
+        self
+    }
+}
+
+impl AsFail for dyn Fail {
+    fn as_fail(&self) -> &dyn Fail {
+        self
+    }
+}
+
+with_std! {
+    use error::Error;
+
+    impl AsFail for Error {
+        fn as_fail(&self) -> &dyn Fail {
+            self.as_fail()
+        }
+    }
+}
diff --git a/src/backtrace/internal.rs b/src/backtrace/internal.rs
new file mode 100644 (file)
index 0000000..5e42120
--- /dev/null
@@ -0,0 +1,132 @@
+use std::cell::UnsafeCell;
+use std::env;
+use std::ffi::OsString;
+use std::fmt;
+#[allow(deprecated)] // to allow for older Rust versions (<1.24)
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::Mutex;
+
+pub use super::backtrace::Backtrace;
+
+const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE";
+const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE";
+
+pub(super) struct InternalBacktrace {
+    backtrace: Option<MaybeResolved>,
+}
+
+struct MaybeResolved {
+    resolved: Mutex<bool>,
+    backtrace: UnsafeCell<Backtrace>,
+}
+
+unsafe impl Send for MaybeResolved {}
+unsafe impl Sync for MaybeResolved {}
+
+impl InternalBacktrace {
+    pub(super) fn new() -> InternalBacktrace {
+        #[allow(deprecated)] // to allow for older Rust versions (<1.24)
+        static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT;
+
+        match ENABLED.load(Ordering::SeqCst) {
+            0 => {
+                let enabled = is_backtrace_enabled(|var| env::var_os(var));
+                ENABLED.store(enabled as usize + 1, Ordering::SeqCst);
+                if !enabled {
+                    return InternalBacktrace { backtrace: None }
+                }
+            }
+            1 => return InternalBacktrace { backtrace: None },
+            _ => {}
+        }
+
+        InternalBacktrace {
+            backtrace: Some(MaybeResolved {
+                resolved: Mutex::new(false),
+                backtrace: UnsafeCell::new(Backtrace::new_unresolved()),
+            }),
+        }
+    }
+
+    pub(super) fn none() -> InternalBacktrace {
+        InternalBacktrace { backtrace: None }
+    }
+
+    pub(super) fn as_backtrace(&self) -> Option<&Backtrace> {
+        let bt = match self.backtrace {
+            Some(ref bt) => bt,
+            None => return None,
+        };
+        let mut resolved = bt.resolved.lock().unwrap();
+        unsafe {
+            if !*resolved {
+                (*bt.backtrace.get()).resolve();
+                *resolved = true;
+            }
+            Some(&*bt.backtrace.get())
+        }
+    }
+
+    pub(super) fn is_none(&self) -> bool {
+        self.backtrace.is_none()
+    }
+}
+
+impl fmt::Debug for InternalBacktrace {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("InternalBacktrace")
+            .field("backtrace", &self.as_backtrace())
+            .finish()
+    }
+}
+
+fn is_backtrace_enabled<F: Fn(&str) -> Option<OsString>>(get_var: F) -> bool {
+    match get_var(FAILURE_BACKTRACE) {
+        Some(ref val) if val != "0" => true,
+        Some(ref val) if val == "0" => false,
+        _ => match get_var(GENERAL_BACKTRACE) {
+            Some(ref val) if val != "0" => true,
+            _                           => false,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    const YEA: Option<&str> = Some("1");
+    const NAY: Option<&str> = Some("0");
+    const NOT_SET: Option<&str> = None;
+
+    macro_rules! test_enabled {
+        (failure: $failure:ident, general: $general:ident => $result:expr) => {{
+            assert_eq!(is_backtrace_enabled(|var| match var {
+                FAILURE_BACKTRACE   => $failure.map(OsString::from),
+                GENERAL_BACKTRACE   => $general.map(OsString::from),
+                _                   => panic!()
+            }), $result);
+        }}
+    }
+
+    #[test]
+    fn always_enabled_if_failure_is_set_to_yes() {
+        test_enabled!(failure: YEA, general: YEA => true);
+        test_enabled!(failure: YEA, general: NOT_SET => true);
+        test_enabled!(failure: YEA, general: NAY => true);
+    }
+
+    #[test]
+    fn never_enabled_if_failure_is_set_to_no() {
+        test_enabled!(failure: NAY, general: YEA => false);
+        test_enabled!(failure: NAY, general: NOT_SET => false);
+        test_enabled!(failure: NAY, general: NAY => false);
+    }
+
+    #[test]
+    fn follows_general_if_failure_is_not_set() {
+        test_enabled!(failure: NOT_SET, general: YEA => true);
+        test_enabled!(failure: NOT_SET, general: NOT_SET => false);
+        test_enabled!(failure: NOT_SET, general: NAY => false);
+    }
+}
diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs
new file mode 100644 (file)
index 0000000..9eba16d
--- /dev/null
@@ -0,0 +1,159 @@
+use core::fmt::{self, Debug, Display};
+
+macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) }
+macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) }
+
+without_backtrace! {
+    /// A `Backtrace`.
+    ///
+    /// This is an opaque wrapper around the backtrace provided by
+    /// libbacktrace. A variety of optimizations have been performed to avoid
+    /// unnecessary or ill-advised work:
+    ///
+    /// - If this crate is compiled in `no_std` compatible mode, `Backtrace`
+    ///   is an empty struct, and will be completely compiled away.
+    /// - If this crate is run without the `RUST_BACKTRACE` environmental
+    ///   variable enabled, the backtrace will not be generated at runtime.
+    /// - Even if a backtrace is generated, the most expensive part of
+    ///   generating a backtrace is symbol resolution. This backtrace does not
+    ///   perform symbol resolution until it is actually read (e.g. by
+    ///   printing it). If the Backtrace is never used for anything, symbols
+    ///   never get resolved.
+    ///
+    /// Even with these optimizations, including a backtrace in your failure
+    /// may not be appropriate to your use case. You are not required to put a
+    /// backtrace in a custom `Fail` type.
+    ///
+    /// > (We have detected that this crate was documented with no_std
+    /// > compatibility turned on. The version of this crate that has been
+    /// > documented here will never generate a backtrace.)
+    pub struct Backtrace {
+        _secret: (),
+    }
+
+    impl Backtrace {
+        /// Constructs a new backtrace. This will only create a real backtrace
+        /// if the crate is compiled in std mode and the `RUST_BACKTRACE`
+        /// environmental variable is activated.
+        ///
+        /// > (We have detected that this crate was documented with no_std
+        /// > compatibility turned on. The version of this crate that has been
+        /// > documented here will never generate a backtrace.)
+        pub fn new() -> Backtrace {
+            Backtrace { _secret: () }
+        }
+
+        #[cfg(feature = "std")]
+        pub(crate) fn none() -> Backtrace {
+            Backtrace { _secret: () }
+        }
+
+        #[cfg(feature = "std")]
+        pub(crate) fn is_none(&self) -> bool {
+            true
+        }
+
+        /// Returns true if displaying this backtrace would be an empty string.
+        ///
+        /// > (We have detected that this crate was documented with no_std
+        /// > compatibility turned on. The version of this crate that has been
+        /// > documented here will never generate a backtrace and this method
+        /// > will always return true.)
+        pub fn is_empty(&self) -> bool {
+            true
+        }
+    }
+
+    impl Default for Backtrace {
+        fn default() -> Backtrace {
+            Backtrace::new()
+        }
+    }
+
+    impl Debug for Backtrace {
+        fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+            Ok(())
+        }
+    }
+
+    impl Display for Backtrace {
+        fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+            Ok(())
+        }
+    }
+}
+
+with_backtrace! {
+    extern crate backtrace;
+
+    mod internal;
+
+    use self::internal::InternalBacktrace;
+
+    /// A `Backtrace`.
+    ///
+    /// This is an opaque wrapper around the backtrace provided by
+    /// libbacktrace. A variety of optimizations have been performed to avoid
+    /// unnecessary or ill-advised work:
+    ///
+    /// - If this crate is compiled in `no_std` compatible mode, `Backtrace`
+    ///   is an empty struct, and will be completely compiled away.
+    /// - If this crate is run without the `RUST_BACKTRACE` environmental
+    ///   variable enabled, the backtrace will not be generated at runtime.
+    /// - Even if a backtrace is generated, the most expensive part of
+    ///   generating a backtrace is symbol resolution. This backtrace does not
+    ///   perform symbol resolution until it is actually read (e.g. by
+    ///   printing it). If the Backtrace is never used for anything, symbols
+    ///   never get resolved.
+    ///
+    /// Even with these optimizations, including a backtrace in your failure
+    /// may not be appropriate to your use case. You are not required to put a
+    /// backtrace in a custom `Fail` type.
+    pub struct Backtrace {
+        internal: InternalBacktrace
+    }
+
+    impl Backtrace {
+        /// Constructs a new backtrace. This will only create a real backtrace
+        /// if the crate is compiled in std mode and the `RUST_BACKTRACE`
+        /// environmental variable is activated.
+        pub fn new() -> Backtrace {
+            Backtrace { internal: InternalBacktrace::new() }
+        }
+
+        pub(crate) fn none() -> Backtrace {
+            Backtrace { internal: InternalBacktrace::none() }
+        }
+
+        pub(crate) fn is_none(&self) -> bool {
+            self.internal.is_none()
+        }
+
+        /// Returns true if displaying this backtrace would be an empty string.
+        pub fn is_empty(&self) -> bool {
+            self.internal.is_none()
+        }
+    }
+
+    impl Default for Backtrace {
+        fn default() -> Backtrace {
+            Backtrace::new()
+        }
+    }
+
+    impl Debug for Backtrace {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            if let Some(bt) = self.internal.as_backtrace() {
+                Debug::fmt(bt, f)
+            } else { Ok(()) }
+        }
+    }
+
+    impl Display for Backtrace {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            if let Some(bt) = self.internal.as_backtrace() {
+                Debug::fmt(bt, f)
+            } else { Ok(()) }
+        }
+    }
+}
diff --git a/src/box_std.rs b/src/box_std.rs
new file mode 100644 (file)
index 0000000..05891db
--- /dev/null
@@ -0,0 +1,19 @@
+use std::error::Error;
+use std::fmt;
+use Fail;
+
+pub struct BoxStd(pub Box<dyn Error + Send + Sync + 'static>);
+
+impl fmt::Display for BoxStd {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
+
+impl fmt::Debug for BoxStd {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.0, f)
+    }
+}
+
+impl Fail for BoxStd {}
diff --git a/src/compat.rs b/src/compat.rs
new file mode 100644 (file)
index 0000000..dec5383
--- /dev/null
@@ -0,0 +1,53 @@
+use core::fmt::{self, Display};
+
+/// A compatibility wrapper around an error type from this crate.
+///
+/// `Compat` implements `std::error::Error`, allowing the types from this
+/// crate to be passed to interfaces that expect a type of that trait.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
+pub struct Compat<E> {
+    pub(crate) error: E,
+}
+
+impl<E: Display> Display for Compat<E> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.error, f)
+    }
+}
+
+impl<E> Compat<E> {
+    /// Unwraps this into the inner error.
+    pub fn into_inner(self) -> E {
+        self.error
+    }
+
+    /// Gets a reference to the inner error.
+    pub fn get_ref(&self) -> &E {
+        &self.error
+    }
+}
+
+with_std! {
+    use std::fmt::Debug;
+    use std::error::Error as StdError;
+
+    use Error;
+
+    impl<E: Display + Debug> StdError for Compat<E> {
+        fn description(&self) -> &'static str {
+            "An error has occurred."
+        }
+    }
+
+    impl From<Error> for Box<dyn StdError> {
+        fn from(error: Error) -> Box<dyn StdError> {
+            Box::new(Compat { error })
+        }
+    }
+
+    impl From<Error> for Box<dyn StdError + Send + Sync> {
+        fn from(error: Error) -> Box<dyn StdError + Send + Sync> {
+            Box::new(Compat { error })
+        }
+    }
+}
diff --git a/src/context.rs b/src/context.rs
new file mode 100644 (file)
index 0000000..b5977e9
--- /dev/null
@@ -0,0 +1,180 @@
+use core::fmt::{self, Debug, Display};
+
+use Fail;
+
+without_std! {
+    /// An error with context around it.
+    ///
+    /// The context is intended to be a human-readable, user-facing explanation for the
+    /// error that has occurred. The underlying error is not assumed to be end-user-relevant
+    /// information.
+    ///
+    /// The `Display` impl for `Context` only prints the human-readable context, while the
+    /// `Debug` impl also prints the underlying error.
+    pub struct Context<D: Display + Send + Sync + 'static> {
+        context: D,
+    }
+
+    impl<D: Display + Send + Sync + 'static> Context<D> {
+        /// Creates a new context without an underlying error message.
+        pub fn new(context: D) -> Context<D> {
+            Context { context }
+        }
+
+        /// Returns a reference to the context provided with this error.
+        pub fn get_context(&self) -> &D {
+            &self.context
+        }
+
+        /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context.
+        pub fn map<F, T>(self, op: F) -> Context<T>
+            where F: FnOnce(D) -> T,
+                  T: Display + Send + Sync + 'static
+        {
+            Context {
+                context: op(self.context),
+            }
+        }
+
+        pub(crate) fn with_err<E: Fail>(context: D, _: E) -> Context<D> {
+            Context { context }
+        }
+    }
+
+    impl<D: Display + Send + Sync + 'static> Fail for Context<D> { }
+
+    impl<D: Display + Send + Sync + 'static> Debug for Context<D> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "{}", self.context)
+        }
+    }
+
+    impl<D: Display + Send + Sync + 'static> Display for Context<D> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "{}", self.context)
+        }
+    }
+
+    #[test]
+    fn test_map() {
+        let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s));
+        assert_eq!(ctx.context, String::from("a string with some more stuff"));
+    }
+}
+
+with_std! {
+    use {Error, Backtrace};
+
+    /// An error with context around it.
+    ///
+    /// The context is intended to be a human-readable, user-facing explanation for the
+    /// error that has occurred. The underlying error is not assumed to be end-user-relevant
+    /// information.
+    ///
+    /// The `Display` impl for `Context` only prints the human-readable context, while the
+    /// `Debug` impl also prints the underlying error.
+    pub struct Context<D: Display + Send + Sync + 'static> {
+        context: D,
+        failure: Either<Backtrace, Error>,
+    }
+
+    impl<D: Display + Send + Sync + 'static> Context<D> {
+        /// Creates a new context without an underlying error message.
+        pub fn new(context: D) -> Context<D> {
+            let failure = Either::This(Backtrace::new());
+            Context { context, failure }
+        }
+
+        /// Returns a reference to the context provided with this error.
+        pub fn get_context(&self) -> &D {
+            &self.context
+        }
+
+        /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context.
+        pub fn map<F, T>(self, op: F) -> Context<T>
+            where F: FnOnce(D) -> T,
+                  T: Display + Send + Sync + 'static
+        {
+            Context {
+                context: op(self.context),
+                failure: self.failure,
+            }
+        }
+
+        pub(crate) fn with_err<E: Into<Error>>(context: D, error: E) -> Context<D> {
+            let failure = Either::That(error.into());
+            Context { context, failure }
+        }
+    }
+
+    impl<D: Display + Send + Sync + 'static> Fail for Context<D> {
+        fn name(&self) -> Option<&str> {
+            self.failure.as_cause().and_then(|x| x.name())
+        }
+
+        fn cause(&self) -> Option<&dyn Fail> {
+            self.failure.as_cause()
+        }
+
+        fn backtrace(&self) -> Option<&Backtrace> {
+            Some(self.failure.backtrace())
+        }
+    }
+
+    impl<D: Display + Send + Sync + 'static> Debug for Context<D> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "{:?}\n\n{}", self.failure, self.context)
+        }
+    }
+
+    impl<D: Display + Send + Sync + 'static> Display for Context<D> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "{}", self.context)
+        }
+    }
+
+    enum Either<A, B> {
+        This(A),
+        That(B),
+    }
+
+    impl Either<Backtrace, Error> {
+        fn backtrace(&self) -> &Backtrace {
+            match *self {
+                Either::This(ref backtrace) => backtrace,
+                Either::That(ref error)     => error.backtrace(),
+            }
+        }
+
+        fn as_cause(&self) -> Option<&dyn Fail> {
+            match *self {
+                Either::This(_)         => None,
+                Either::That(ref error) => Some(error.as_fail())
+            }
+        }
+    }
+
+    impl Debug for Either<Backtrace, Error> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            match *self {
+                Either::This(ref backtrace) => write!(f, "{:?}", backtrace),
+                Either::That(ref error)     => write!(f, "{:?}", error),
+            }
+        }
+    }
+
+    #[test]
+    fn test_map() {
+        let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s));
+        assert_eq!(ctx.context, String::from("a string with some more stuff"));
+    }
+}
+
+impl<D> From<D> for Context<D>
+where
+    D: Display + Send + Sync + 'static,
+{
+    fn from(display: D) -> Context<D> {
+        Context::new(display)
+    }
+}
diff --git a/src/error/error_impl.rs b/src/error/error_impl.rs
new file mode 100644 (file)
index 0000000..6a95d92
--- /dev/null
@@ -0,0 +1,50 @@
+use core::any::TypeId;
+
+use Fail;
+use backtrace::Backtrace;
+
+pub(crate) struct ErrorImpl {
+    inner: Box<Inner<dyn Fail>>,
+}
+
+struct Inner<F: ?Sized + Fail> {
+    backtrace: Backtrace,
+    pub(crate) failure: F,
+}
+
+impl<F: Fail> From<F> for ErrorImpl {
+    fn from(failure: F) -> ErrorImpl {
+        let inner: Inner<F> = {
+            let backtrace = if failure.backtrace().is_none() {
+                Backtrace::new()
+            } else { Backtrace::none() };
+            Inner { failure, backtrace }
+        };
+        ErrorImpl { inner: Box::new(inner) }
+    }
+}
+
+impl ErrorImpl {
+    pub(crate) fn failure(&self) -> &dyn Fail {
+        &self.inner.failure
+    }
+
+    pub(crate) fn failure_mut(&mut self) -> &mut dyn Fail {
+        &mut self.inner.failure
+    }
+
+    pub(crate) fn backtrace(&self) -> &Backtrace {
+        &self.inner.backtrace
+    }
+
+    pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> {
+        if self.failure().__private_get_type_id__() == TypeId::of::<T>() {
+            let ErrorImpl { inner } = self;
+            let casted = unsafe { Box::from_raw(Box::into_raw(inner) as *mut Inner<T>) };
+            let Inner { backtrace:_, failure } = *casted;
+            Ok(failure)
+        } else {
+            Err(self)
+        }
+    }
+}
diff --git a/src/error/error_impl_small.rs b/src/error/error_impl_small.rs
new file mode 100644 (file)
index 0000000..6ff7c78
--- /dev/null
@@ -0,0 +1,132 @@
+use std::heap::{Heap, Alloc, Layout};
+
+use core::mem;
+use core::ptr;
+
+use Fail;
+use backtrace::Backtrace;
+
+pub(crate) struct ErrorImpl {
+    inner: &'static mut Inner,
+}
+
+// Dynamically sized inner value
+struct Inner {
+    backtrace: Backtrace,
+    vtable: *const VTable,
+    failure: FailData,
+}
+
+unsafe impl Send for Inner { }
+unsafe impl Sync for Inner { }
+
+extern {
+    type VTable;
+    type FailData;
+}
+
+#[allow(dead_code)]
+struct InnerRaw<F> {
+    header: InnerHeader,
+    failure: F,
+}
+
+#[allow(dead_code)]
+struct InnerHeader {
+    backtrace: Backtrace,
+    vtable: *const VTable,
+}
+
+struct TraitObject {
+    #[allow(dead_code)]
+    data: *const FailData,
+    vtable: *const VTable,
+}
+
+impl<F: Fail> From<F> for ErrorImpl {
+    fn from(failure: F) -> ErrorImpl {
+        let backtrace = if failure.backtrace().is_none() {
+            Backtrace::new()
+        } else {
+            Backtrace::none()
+        };
+
+        unsafe {
+            let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable;
+
+            let ptr: *mut InnerRaw<F> = match Heap.alloc(Layout::new::<InnerRaw<F>>()) {
+                Ok(p)   => p as *mut InnerRaw<F>,
+                Err(e)  => Heap.oom(e),
+            };
+
+            // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr`
+            ptr::write(ptr, InnerRaw {
+                header: InnerHeader {
+                    backtrace,
+                    vtable,
+                },
+                failure,
+            });
+
+            let inner: &'static mut Inner = mem::transmute(ptr);
+
+            ErrorImpl { inner }
+        }
+    }
+}
+
+impl ErrorImpl {
+    pub(crate) fn failure(&self) -> &Fail {
+        unsafe {
+            mem::transmute::<TraitObject, &Fail>(TraitObject {
+                data: &self.inner.failure as *const FailData,
+                vtable: self.inner.vtable,
+            })
+        }
+    }
+
+    pub(crate) fn failure_mut(&mut self) -> &mut Fail {
+        unsafe {
+            mem::transmute::<TraitObject, &mut Fail>(TraitObject {
+                data: &mut self.inner.failure as *const FailData,
+                vtable: self.inner.vtable,
+            })
+        }
+    }
+
+    pub(crate) fn backtrace(&self) -> &Backtrace {
+        &self.inner.backtrace
+    }
+
+    pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> {
+        let ret: Option<T> = self.failure().downcast_ref().map(|fail| {
+            unsafe {
+                // drop the backtrace
+                let _ = ptr::read(&self.inner.backtrace as *const Backtrace);
+                // read out the fail type
+                ptr::read(fail as *const T)
+            }
+        });
+        match ret {
+            Some(ret) => {
+                // forget self (backtrace is dropped, failure is moved
+                mem::forget(self);
+                Ok(ret)
+            }
+            _ => Err(self)
+        }
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use std::mem::size_of;
+
+    use super::ErrorImpl;
+
+    #[test]
+    fn assert_is_one_word() {
+        assert_eq!(size_of::<ErrorImpl>(), size_of::<usize>());
+    }
+}
diff --git a/src/error/mod.rs b/src/error/mod.rs
new file mode 100644 (file)
index 0000000..842dbba
--- /dev/null
@@ -0,0 +1,248 @@
+use core::fmt::{self, Display, Debug};
+
+use {Causes, Fail};
+use backtrace::Backtrace;
+use context::Context;
+use compat::Compat;
+
+#[cfg(feature = "std")]
+use box_std::BoxStd;
+
+#[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")]
+mod error_impl;
+use self::error_impl::ErrorImpl;
+
+#[cfg(feature = "std")]
+use std::error::Error as StdError;
+
+
+/// The `Error` type, which can contain any failure.
+///
+/// Functions which accumulate many kinds of errors should return this type.
+/// All failures can be converted into it, so functions which catch those
+/// errors can be tried with `?` inside of a function that returns this kind
+/// of error.
+///
+/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace`
+/// information, and can be downcast into the failure that underlies it for
+/// more detailed inspection.
+pub struct Error {
+    imp: ErrorImpl,
+}
+
+impl<F: Fail> From<F> for Error {
+    fn from(failure: F) -> Error {
+        Error {
+            imp: ErrorImpl::from(failure)
+        }
+    }
+}
+
+impl Error {
+    /// Creates an `Error` from `Box<std::error::Error>`.
+    ///
+    /// This method is useful for comparability with code,
+    /// which does not use the `Fail` trait.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::error::Error as StdError;
+    /// use failure::Error;
+    ///
+    /// fn app_fn() -> Result<i32, Error> {
+    ///     let x = library_fn().map_err(Error::from_boxed_compat)?;
+    ///     Ok(x * 2)
+    /// }
+    ///
+    /// fn library_fn() -> Result<i32, Box<StdError + Sync + Send + 'static>> {
+    ///     Ok(92)
+    /// }
+    /// ```
+    #[cfg(feature = "std")]
+    pub fn from_boxed_compat(err: Box<dyn StdError + Sync + Send + 'static>) -> Error {
+        Error::from(BoxStd(err))
+    }
+
+    /// Return a reference to the underlying failure that this `Error`
+    /// contains.
+    pub fn as_fail(&self) -> &dyn Fail {
+        self.imp.failure()
+    }
+
+    /// Returns the name of the underlying fail.
+    pub fn name(&self) -> Option<&str> {
+        self.as_fail().name()
+    }
+
+    /// Returns a reference to the underlying cause of this `Error`. Unlike the
+    /// method on `Fail`, this does not return an `Option`. The `Error` type
+    /// always has an underlying failure.
+    ///
+    /// This method has been deprecated in favor of the [Error::as_fail] method,
+    /// which does the same thing.
+    #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")]
+    pub fn cause(&self) -> &dyn Fail {
+        self.as_fail()
+    }
+
+    /// Gets a reference to the `Backtrace` for this `Error`.
+    ///
+    /// If the failure this wrapped carried a backtrace, that backtrace will
+    /// be returned. Otherwise, the backtrace will have been constructed at
+    /// the point that failure was cast into the `Error` type.
+    pub fn backtrace(&self) -> &Backtrace {
+        self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace())
+    }
+
+    /// Provides context for this `Error`.
+    ///
+    /// This can provide additional information about this error, appropriate
+    /// to the semantics of the current layer. That is, if you have a
+    /// lower-level error, such as an IO error, you can provide additional context
+    /// about what that error means in the context of your function. This
+    /// gives users of this function more information about what has gone
+    /// wrong.
+    ///
+    /// This takes any type that implements `Display`, as well as
+    /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
+    /// or a string literal, or a failure, or some other custom context-carrying
+    /// type.
+    pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> {
+        Context::with_err(context, self)
+    }
+
+    /// Wraps `Error` in a compatibility type.
+    ///
+    /// This type implements the `Error` trait from `std::error`. If you need
+    /// to pass failure's `Error` to an interface that takes any `Error`, you
+    /// can use this method to get a compatible type.
+    pub fn compat(self) -> Compat<Error> {
+        Compat { error: self }
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type.
+    ///
+    /// This downcasts by value, returning an owned `T` if the underlying
+    /// failure is of the type `T`. For this reason it returns a `Result` - in
+    /// the case that the underlying error is of a different type, the
+    /// original `Error` is returned.
+    pub fn downcast<T: Fail>(self) -> Result<T, Error> {
+        self.imp.downcast().map_err(|imp| Error { imp })
+    }
+
+    /// Returns the "root cause" of this error - the last value in the
+    /// cause chain which does not return an underlying `cause`.
+    pub fn find_root_cause(&self) -> &dyn Fail {
+        self.as_fail().find_root_cause()
+    }
+
+    /// Returns a iterator over the causes of this error with the cause
+    /// of the fail as the first item and the `root_cause` as the final item.
+    ///
+    /// Use `iter_chain` to also include the fail of this error itself.
+    pub fn iter_causes(&self) -> Causes {
+        self.as_fail().iter_causes()
+    }
+
+    /// Returns a iterator over all fails up the chain from the current
+    /// as the first item up to the `root_cause` as the final item.
+    ///
+    /// This means that the chain also includes the fail itself which
+    /// means that it does *not* start with `cause`.  To skip the outermost
+    /// fail use `iter_causes` instead.
+    pub fn iter_chain(&self) -> Causes {
+        self.as_fail().iter_chain()
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type by
+    /// reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
+        self.imp.failure().downcast_ref()
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type by
+    /// mutable reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
+        self.imp.failure_mut().downcast_mut()
+    }
+
+    /// Deprecated alias to `find_root_cause`.
+    #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")]
+    pub fn root_cause(&self) -> &dyn Fail {
+        ::find_root_cause(self.as_fail())
+    }
+
+    /// Deprecated alias to `iter_causes`.
+    #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
+    pub fn causes(&self) -> Causes {
+        Causes { fail: Some(self.as_fail()) }
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.imp.failure(), f)
+    }
+}
+
+impl Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let backtrace = self.imp.backtrace();
+        if backtrace.is_none() {
+            Debug::fmt(&self.imp.failure(), f)
+        } else {
+            write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace)
+        }
+    }
+}
+
+impl AsRef<dyn Fail> for Error {
+    fn as_ref(&self) -> &dyn Fail {
+        self.as_fail()
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::io;
+    use super::Error;
+
+    fn assert_just_data<T: Send + Sync + 'static>() { }
+
+    #[test]
+    fn assert_error_is_just_data() {
+        assert_just_data::<Error>();
+    }
+
+    #[test]
+    fn methods_seem_to_work() {
+        let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test");
+        let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
+        assert!(error.downcast_ref::<io::Error>().is_some());
+        let _: ::Backtrace = *error.backtrace();
+        assert_eq!(format!("{:?}", io_error), format!("{:?}", error));
+        assert_eq!(format!("{}", io_error), format!("{}", error));
+        drop(error);
+        assert!(true);
+    }
+
+    #[test]
+    fn downcast_can_be_used() {
+        let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
+        {
+            let real_io_error_ref = error.downcast_ref::<io::Error>().unwrap();
+            assert_eq!(real_io_error_ref.to_string(), "test");
+        }
+        {
+            let real_io_error_mut = error.downcast_mut::<io::Error>().unwrap();
+            assert_eq!(real_io_error_mut.to_string(), "test");
+        }
+        let real_io_error = error.downcast::<io::Error>().unwrap();
+        assert_eq!(real_io_error.to_string(), "test");
+    }
+}
diff --git a/src/error_message.rs b/src/error_message.rs
new file mode 100644 (file)
index 0000000..560d317
--- /dev/null
@@ -0,0 +1,32 @@
+use core::fmt::{self, Display, Debug};
+
+use Fail;
+use Error;
+
+/// Constructs a `Fail` type from a string.
+///
+/// This is a convenient way to turn a string into an error value that
+/// can be passed around, if you do not want to create a new `Fail` type for
+/// this use case.
+pub fn err_msg<D: Display + Debug + Sync + Send + 'static>(msg: D) -> Error {
+    Error::from(ErrorMessage { msg })
+}
+
+/// A `Fail` type that just contains an error message. You can construct
+/// this from the `err_msg` function.
+#[derive(Debug)]
+struct ErrorMessage<D: Display + Debug + Sync + Send + 'static> {
+    msg: D,
+}
+
+impl<D: Display + Debug + Sync + Send + 'static> Fail for ErrorMessage<D> {
+    fn name(&self) -> Option<&str> {
+        Some("failure::ErrorMessage")
+    }
+}
+
+impl<D: Display + Debug + Sync + Send + 'static> Display for ErrorMessage<D> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.msg, f)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..41a45ba
--- /dev/null
@@ -0,0 +1,307 @@
+//! An experimental new error-handling library. Guide-style introduction
+//! is available [here](https://boats.gitlab.io/failure/).
+//!
+//! The primary items exported by this library are:
+//!
+//! - `Fail`: a new trait for custom error types in Rust.
+//! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them
+//!   at higher levels.
+//!
+//! As a general rule, library authors should create their own error types and
+//! implement `Fail` for them, whereas application authors should primarily
+//! deal with the `Error` type. There are exceptions to this rule, though, in
+//! both directions, and users should do whatever seems most appropriate to
+//! their situation.
+//!
+//! ## Backtraces
+//!
+//! Backtraces are disabled by default. To turn backtraces on, enable
+//! the `backtrace` Cargo feature and set the `RUST_BACKTRACE` environment
+//! variable to a non-zero value (this also enables backtraces for panics).
+//! Use the `RUST_FAILURE_BACKTRACE` variable to enable or disable backtraces
+//! for `failure` specifically.
+#![cfg_attr(not(feature = "std"), no_std)]
+#![deny(missing_docs)]
+#![deny(warnings)]
+#![cfg_attr(feature = "small-error", feature(extern_types, allocator_api))]
+
+macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) }
+macro_rules! without_std { ($($i:item)*) => ($(#[cfg(not(feature = "std"))]$i)*) }
+
+// Re-export libcore using an alias so that the macros can work without
+// requiring `extern crate core` downstream.
+#[doc(hidden)]
+pub extern crate core as _core;
+
+mod as_fail;
+mod backtrace;
+#[cfg(feature = "std")]
+mod box_std;
+mod compat;
+mod context;
+mod result_ext;
+
+use core::any::TypeId;
+use core::fmt::{Debug, Display};
+
+pub use as_fail::AsFail;
+pub use backtrace::Backtrace;
+pub use compat::Compat;
+pub use context::Context;
+pub use result_ext::ResultExt;
+
+#[cfg(feature = "failure_derive")]
+#[allow(unused_imports)]
+#[macro_use]
+extern crate failure_derive;
+
+#[cfg(feature = "failure_derive")]
+#[doc(hidden)]
+pub use failure_derive::*;
+
+with_std! {
+    extern crate core;
+
+    mod sync_failure;
+    pub use sync_failure::SyncFailure;
+
+    mod error;
+
+    use std::error::Error as StdError;
+
+    pub use error::Error;
+
+    /// A common result with an `Error`.
+    pub type Fallible<T> = Result<T, Error>;
+
+    mod macros;
+    mod error_message;
+    pub use error_message::err_msg;
+}
+
+/// The `Fail` trait.
+///
+/// Implementors of this trait are called 'failures'.
+///
+/// All error types should implement `Fail`, which provides a baseline of
+/// functionality that they all share.
+///
+/// `Fail` has no required methods, but it does require that your type
+/// implement several other traits:
+///
+/// - `Display`: to print a user-friendly representation of the error.
+/// - `Debug`: to print a verbose, developer-focused representation of the
+///   error.
+/// - `Send + Sync`: Your error type is required to be safe to transfer to and
+///   reference from another thread
+///
+/// Additionally, all failures must be `'static`. This enables downcasting.
+///
+/// `Fail` provides several methods with default implementations. Two of these
+/// may be appropriate to override depending on the definition of your
+/// particular failure: the `cause` and `backtrace` methods.
+///
+/// The `failure_derive` crate provides a way to derive the `Fail` trait for
+/// your type. Additionally, all types that already implement
+/// `std::error::Error`, and are also `Send`, `Sync`, and `'static`, implement
+/// `Fail` by a blanket impl.
+pub trait Fail: Display + Debug + Send + Sync + 'static {
+    /// Returns the "name" of the error.
+    /// 
+    /// This is typically the type name. Not all errors will implement
+    /// this. This method is expected to be most useful in situations
+    /// where errors need to be reported to external instrumentation systems 
+    /// such as crash reporters.
+    fn name(&self) -> Option<&str> {
+        None
+    }
+
+    /// Returns a reference to the underlying cause of this failure, if it
+    /// is an error that wraps other errors.
+    ///
+    /// Returns `None` if this failure does not have another error as its
+    /// underlying cause. By default, this returns `None`.
+    ///
+    /// This should **never** return a reference to `self`, but only return
+    /// `Some` when it can return a **different** failure. Users may loop
+    /// over the cause chain, and returning `self` would result in an infinite
+    /// loop.
+    fn cause(&self) -> Option<&dyn Fail> {
+        None
+    }
+
+    /// Returns a reference to the `Backtrace` carried by this failure, if it
+    /// carries one.
+    ///
+    /// Returns `None` if this failure does not carry a backtrace. By
+    /// default, this returns `None`.
+    fn backtrace(&self) -> Option<&Backtrace> {
+        None
+    }
+
+    /// Provides context for this failure.
+    ///
+    /// This can provide additional information about this error, appropriate
+    /// to the semantics of the current layer. That is, if you have a
+    /// lower-level error, such as an IO error, you can provide additional context
+    /// about what that error means in the context of your function. This
+    /// gives users of this function more information about what has gone
+    /// wrong.
+    ///
+    /// This takes any type that implements `Display`, as well as
+    /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
+    /// or a string literal, or another failure, or some other custom context-carrying
+    /// type.
+    fn context<D>(self, context: D) -> Context<D>
+    where
+        D: Display + Send + Sync + 'static,
+        Self: Sized,
+    {
+        Context::with_err(context, self)
+    }
+
+    /// Wraps this failure in a compatibility wrapper that implements
+    /// `std::error::Error`.
+    ///
+    /// This allows failures  to be compatible with older crates that
+    /// expect types that implement the `Error` trait from `std::error`.
+    fn compat(self) -> Compat<Self>
+    where
+        Self: Sized,
+    {
+        Compat { error: self }
+    }
+
+    #[doc(hidden)]
+    #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
+    fn causes(&self) -> Causes
+    where
+        Self: Sized,
+    {
+        Causes { fail: Some(self) }
+    }
+
+    #[doc(hidden)]
+    #[deprecated(
+        since = "0.1.2",
+        note = "please use the 'find_root_cause()' method instead"
+    )]
+    fn root_cause(&self) -> &dyn Fail
+    where
+        Self: Sized,
+    {
+        find_root_cause(self)
+    }
+
+    #[doc(hidden)]
+    fn __private_get_type_id__(&self) -> TypeId {
+        TypeId::of::<Self>()
+    }
+}
+
+impl dyn Fail {
+    /// Attempts to downcast this failure to a concrete type by reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
+        if self.__private_get_type_id__() == TypeId::of::<T>() {
+            unsafe { Some(&*(self as *const dyn Fail as *const T)) }
+        } else {
+            None
+        }
+    }
+
+    /// Attempts to downcast this failure to a concrete type by mutable
+    /// reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
+        if self.__private_get_type_id__() == TypeId::of::<T>() {
+            unsafe { Some(&mut *(self as *mut dyn Fail as *mut T)) }
+        } else {
+            None
+        }
+    }
+
+    /// Returns the "root cause" of this `Fail` - the last value in the
+    /// cause chain which does not return an underlying `cause`.
+    ///
+    /// If this type does not have a cause, `self` is returned, because
+    /// it is its own root cause.
+    ///
+    /// This is equivalent to iterating over `iter_causes()` and taking
+    /// the last item.
+    pub fn find_root_cause(&self) -> &dyn Fail {
+        find_root_cause(self)
+    }
+
+    /// Returns a iterator over the causes of this `Fail` with the cause
+    /// of this fail as the first item and the `root_cause` as the final item.
+    ///
+    /// Use `iter_chain` to also include the fail itself.
+    pub fn iter_causes(&self) -> Causes {
+        Causes { fail: self.cause() }
+    }
+
+    /// Returns a iterator over all fails up the chain from the current
+    /// as the first item up to the `root_cause` as the final item.
+    ///
+    /// This means that the chain also includes the fail itself which
+    /// means that it does *not* start with `cause`.  To skip the outermost
+    /// fail use `iter_causes` instead.
+    pub fn iter_chain(&self) -> Causes {
+        Causes { fail: Some(self) }
+    }
+
+    /// Deprecated alias to `find_root_cause`.
+    #[deprecated(
+        since = "0.1.2",
+        note = "please use the 'find_root_cause()' method instead"
+    )]
+    pub fn root_cause(&self) -> &dyn Fail {
+        find_root_cause(self)
+    }
+
+    /// Deprecated alias to `iter_chain`.
+    #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
+    pub fn causes(&self) -> Causes {
+        Causes { fail: Some(self) }
+    }
+}
+
+#[cfg(feature = "std")]
+impl<E: StdError + Send + Sync + 'static> Fail for E {}
+
+#[cfg(feature = "std")]
+impl Fail for Box<dyn Fail> {
+    fn cause(&self) -> Option<&dyn Fail> {
+        (**self).cause()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        (**self).backtrace()
+    }
+}
+
+/// A iterator over the causes of a `Fail`
+pub struct Causes<'f> {
+    fail: Option<&'f dyn Fail>,
+}
+
+impl<'f> Iterator for Causes<'f> {
+    type Item = &'f dyn Fail;
+    fn next(&mut self) -> Option<&'f dyn Fail> {
+        self.fail.map(|fail| {
+            self.fail = fail.cause();
+            fail
+        })
+    }
+}
+
+fn find_root_cause(mut fail: &dyn Fail) -> &dyn Fail {
+    while let Some(cause) = fail.cause() {
+        fail = cause;
+    }
+
+    fail
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644 (file)
index 0000000..c0a9dad
--- /dev/null
@@ -0,0 +1,64 @@
+/// Exits a function early with an `Error`.
+///
+/// The `bail!` macro provides an easy way to exit a function. `bail!(X)` is
+/// equivalent to writing:
+///
+/// ```rust,ignore
+/// return Err(format_err!(X))
+/// ```
+#[macro_export]
+macro_rules! bail {
+    ($e:expr) => {
+        return Err($crate::err_msg($e));
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        return Err($crate::err_msg(format!($fmt, $($arg)*)));
+    };
+}
+
+/// Exits a function early with an `Error` if the condition is not satisfied.
+///
+/// Similar to `assert!`, `ensure!` takes a condition and exits the function
+/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`,
+/// it does not panic.
+#[macro_export(local_inner_macros)]
+macro_rules! ensure {
+    ($cond:expr) => {
+        if !($cond) {
+            bail!("{}", _failure__stringify!($cond));
+        }
+    };
+    ($cond:expr, $e:expr) => {
+        if !($cond) {
+            bail!($e);
+        }
+    };
+    ($cond:expr, $fmt:expr, $($arg:tt)*) => {
+        if !($cond) {
+            bail!($fmt, $($arg)*);
+        }
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! _failure__stringify {
+    ($($inner:tt)*) => {
+        stringify! { $($inner)* }
+    }
+}
+
+/// Constructs an `Error` using the standard string interpolation syntax.
+///
+/// ```rust
+/// #[macro_use] extern crate failure;
+///
+/// fn main() {
+///     let code = 101;
+///     let err = format_err!("Error code: {}", code);
+/// }
+/// ```
+#[macro_export]
+macro_rules! format_err {
+    ($($arg:tt)*) => { $crate::err_msg(format!($($arg)*)) }
+}
diff --git a/src/result_ext.rs b/src/result_ext.rs
new file mode 100644 (file)
index 0000000..f4125cd
--- /dev/null
@@ -0,0 +1,203 @@
+use core::fmt::Display;
+
+use {Compat, Context, Fail};
+
+/// Extension methods for `Result`.
+pub trait ResultExt<T, E> {
+    /// Wraps the error in `Compat` to make it compatible with older error
+    /// handling APIs that expect `std::error::Error`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # fn main() {
+    /// #    tests::run_test();
+    /// # }
+    /// #
+    /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } }
+    /// #  
+    /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests {
+    /// use std::error::Error;
+    /// # use std::fmt;
+    /// #
+    /// # extern crate failure;
+    /// #
+    /// # use tests::failure::ResultExt;
+    /// #
+    /// # #[derive(Debug)]
+    /// struct CustomError;
+    ///
+    /// impl Error for CustomError {
+    ///     fn description(&self) -> &str {
+    ///         "My custom error message"
+    ///     }
+    ///
+    ///     fn cause(&self) -> Option<&Error> {
+    ///         None
+    ///     }
+    /// }
+    /// #
+    /// # impl fmt::Display for CustomError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    /// #         write!(f, "{}", self.description())
+    /// #     }
+    /// # }
+    /// #
+    /// # pub fn run_test() {
+    ///
+    /// let x = (|| -> Result<(), failure::Error> {
+    ///     Err(CustomError).compat()?
+    /// })().with_context(|e| {
+    ///     format!("An error occured: {}", e)
+    /// }).unwrap_err();
+    ///
+    /// let x = format!("{}", x);
+    ///
+    /// assert_eq!(x, "An error occured: My custom error message");
+    /// # }
+    ///
+    /// # }
+    /// ```
+    fn compat(self) -> Result<T, Compat<E>>;
+
+    /// Wraps the error type in a context type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #[cfg(all(feature = "std", feature = "derive"))]
+    /// # #[macro_use] extern crate failure;
+    /// #
+    /// # #[cfg(all(feature = "std", feature = "derive"))]
+    /// # #[macro_use] extern crate failure_derive;
+    /// #
+    /// # fn main() {
+    /// #    tests::run_test();
+    /// # }
+    /// #
+    /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } }
+    /// #
+    /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests {
+    /// #
+    /// # use failure::{self, ResultExt};
+    /// #
+    /// #[derive(Fail, Debug)]
+    /// #[fail(display = "")]
+    /// struct CustomError;
+    /// #
+    /// # pub fn run_test() {
+    ///  
+    /// let x = (|| -> Result<(), failure::Error> {
+    ///     Err(CustomError)?
+    /// })().context(format!("An error occured")).unwrap_err();
+    ///
+    /// let x = format!("{}", x);
+    ///
+    /// assert_eq!(x, "An error occured");
+    /// # }
+    ///
+    /// # }
+    /// ```
+    fn context<D>(self, context: D) -> Result<T, Context<D>>
+    where
+        D: Display + Send + Sync + 'static;
+
+    /// Wraps the error type in a context type generated by looking at the
+    /// error value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #[cfg(all(feature = "std", feature = "derive"))]
+    /// # #[macro_use] extern crate failure;
+    /// #
+    /// # #[cfg(all(feature = "std", feature = "derive"))]
+    /// # #[macro_use] extern crate failure_derive;
+    /// #
+    /// # fn main() {
+    /// #    tests::run_test();
+    /// # }
+    /// #
+    /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } }
+    /// #
+    /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests {
+    /// #
+    /// # use failure::{self, ResultExt};
+    /// #
+    /// #[derive(Fail, Debug)]
+    /// #[fail(display = "My custom error message")]
+    /// struct CustomError;
+    /// #
+    /// # pub fn run_test() {
+    ///
+    /// let x = (|| -> Result<(), failure::Error> {
+    ///     Err(CustomError)?
+    /// })().with_context(|e| {
+    ///     format!("An error occured: {}", e)
+    /// }).unwrap_err();
+    ///
+    /// let x = format!("{}", x);
+    ///
+    /// assert_eq!(x, "An error occured: My custom error message");
+    /// # }
+    ///
+    /// # }
+    /// ```
+    fn with_context<F, D>(self, f: F) -> Result<T, Context<D>>
+    where
+        F: FnOnce(&E) -> D,
+        D: Display + Send + Sync + 'static;
+}
+
+impl<T, E> ResultExt<T, E> for Result<T, E>
+where
+    E: Fail,
+{
+    fn compat(self) -> Result<T, Compat<E>> {
+        self.map_err(|err| err.compat())
+    }
+
+    fn context<D>(self, context: D) -> Result<T, Context<D>>
+    where
+        D: Display + Send + Sync + 'static,
+    {
+        self.map_err(|failure| failure.context(context))
+    }
+
+    fn with_context<F, D>(self, f: F) -> Result<T, Context<D>>
+    where
+        F: FnOnce(&E) -> D,
+        D: Display + Send + Sync + 'static,
+    {
+        self.map_err(|failure| {
+            let context = f(&failure);
+            failure.context(context)
+        })
+    }
+}
+
+with_std! {
+    use Error;
+
+    impl<T> ResultExt<T, Error> for Result<T, Error> {
+        fn compat(self) -> Result<T, Compat<Error>> {
+            self.map_err(|err| err.compat())
+        }
+
+        fn context<D>(self, context: D) -> Result<T, Context<D>> where
+            D: Display + Send + Sync + 'static
+        {
+            self.map_err(|failure| failure.context(context))
+        }
+
+        fn with_context<F, D>(self, f: F) -> Result<T, Context<D>> where
+            F: FnOnce(&Error) -> D,
+            D: Display + Send + Sync + 'static
+        {
+            self.map_err(|failure| {
+                let context = f(&failure);
+                failure.context(context)
+            })
+        }
+    }
+}
diff --git a/src/small_error.rs b/src/small_error.rs
new file mode 100644 (file)
index 0000000..09646e3
--- /dev/null
@@ -0,0 +1,264 @@
+use core::fmt::{self, Display, Debug};
+use std::heap::{Heap, Alloc, Layout};
+
+use core::mem;
+use core::ptr;
+
+use {Causes, Fail};
+use backtrace::Backtrace;
+use context::Context;
+use compat::Compat;
+
+/// The `Error` type, which can contain any failure.
+///
+/// Functions which accumulate many kinds of errors should return this type.
+/// All failures can be converted into it, so functions which catch those
+/// errors can be tried with `?` inside of a function that returns this kind
+/// of error.
+///
+/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace`
+/// information, and can be downcast into the failure that underlies it for
+/// more detailed inspection.
+pub struct Error {
+    inner: &'static mut Inner,
+}
+
+// Dynamically sized inner value
+struct Inner {
+    backtrace: Backtrace,
+    vtable: *const VTable,
+    failure: FailData,
+}
+
+unsafe impl Send for Inner { }
+unsafe impl Sync for Inner { }
+
+extern {
+    type VTable;
+    type FailData;
+}
+
+struct InnerRaw<F> {
+    header: InnerHeader,
+    failure: F,
+}
+
+struct InnerHeader {
+    backtrace: Backtrace,
+    vtable: *const VTable,
+}
+
+struct TraitObject {
+    #[allow(dead_code)]
+    data: *const FailData,
+    vtable: *const VTable,
+}
+
+impl<F: Fail> From<F> for Error {
+    fn from(failure: F) -> Error {
+        let backtrace = if failure.backtrace().is_none() {
+            Backtrace::new()
+        } else {
+            Backtrace::none()
+        };
+
+        unsafe {
+            let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable;
+
+            let ptr: *mut InnerRaw<F> = match Heap.alloc(Layout::new::<InnerRaw<F>>()) {
+                Ok(p)   => p as *mut InnerRaw<F>,
+                Err(e)  => Heap.oom(e),
+            };
+
+            // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr`
+            ptr::write(ptr, InnerRaw {
+                header: InnerHeader {
+                    backtrace,
+                    vtable,
+                },
+                failure,
+            });
+
+            let inner: &'static mut Inner = mem::transmute(ptr);
+
+            Error { inner }
+        }
+    }
+}
+
+impl Inner {
+    fn failure(&self) -> &Fail {
+        unsafe {
+            mem::transmute::<TraitObject, &Fail>(TraitObject {
+                data: &self.failure as *const FailData,
+                vtable: self.vtable,
+            })
+        }
+    }
+
+    fn failure_mut(&mut self) -> &mut Fail {
+        unsafe {
+            mem::transmute::<TraitObject, &mut Fail>(TraitObject {
+                data: &mut self.failure as *const FailData,
+                vtable: self.vtable,
+            })
+        }
+    }
+}
+
+impl Error {
+    /// Returns a reference to the underlying cause of this `Error`. Unlike the
+    /// method on `Fail`, this does not return an `Option`. The `Error` type
+    /// always has an underlying failure.
+    pub fn cause(&self) -> &Fail {
+        self.inner.failure()
+    }
+
+    /// Gets a reference to the `Backtrace` for this `Error`.
+    ///
+    /// If the failure this wrapped carried a backtrace, that backtrace will
+    /// be returned. Otherwise, the backtrace will have been constructed at
+    /// the point that failure was cast into the `Error` type.
+    pub fn backtrace(&self) -> &Backtrace {
+        self.inner.failure().backtrace().unwrap_or(&self.inner.backtrace)
+    }
+
+    /// Provides context for this `Error`.
+    ///
+    /// This can provide additional information about this error, appropriate
+    /// to the semantics of the current layer. That is, if you have a
+    /// lower-level error, such as an IO error, you can provide additional context
+    /// about what that error means in the context of your function. This
+    /// gives users of this function more information about what has gone
+    /// wrong.
+    ///
+    /// This takes any type that implements `Display`, as well as
+    /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
+    /// or a string literal, or a failure, or some other custom context-carrying
+    /// type.
+    pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> {
+        Context::with_err(context, self)
+    }
+
+    /// Wraps `Error` in a compatibility type.
+    ///
+    /// This type implements the `Error` trait from `std::error`. If you need
+    /// to pass failure's `Error` to an interface that takes any `Error`, you
+    /// can use this method to get a compatible type.
+    pub fn compat(self) -> Compat<Error> {
+        Compat { error: self }
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type.
+    ///
+    /// This downcasts by value, returning an owned `T` if the underlying
+    /// failure is of the type `T`. For this reason it returns a `Result` - in
+    /// the case that the underlying error is of a different type, the
+    /// original `Error` is returned.
+    pub fn downcast<T: Fail>(self) -> Result<T, Error> {
+        let ret: Option<T> = self.downcast_ref().map(|fail| {
+            unsafe {
+                // drop the backtrace
+                let _ = ptr::read(&self.inner.backtrace as *const Backtrace);
+                // read out the fail type
+                ptr::read(fail as *const T)
+            }
+        });
+        match ret {
+            Some(ret) => {
+                // forget self (backtrace is dropped, failure is moved
+                mem::forget(self);
+                Ok(ret)
+            }
+            _ => Err(self)
+        }
+    }
+
+    /// Returns the "root cause" of this error - the last value in the
+    /// cause chain which does not return an underlying `cause`.
+    pub fn root_cause(&self) -> &Fail {
+        ::find_root_cause(self.cause())
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type by
+    /// reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
+        self.inner.failure().downcast_ref()
+    }
+
+    /// Attempts to downcast this `Error` to a particular `Fail` type by
+    /// mutable reference.
+    ///
+    /// If the underlying error is not of type `T`, this will return `None`.
+    pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
+        self.inner.failure_mut().downcast_mut()
+    }
+
+    /// Returns a iterator over the causes of the `Error`, beginning with
+    /// the failure returned by the `cause` method and ending with the failure
+    /// returned by `root_cause`.
+    pub fn causes(&self) -> Causes {
+        Causes { fail: Some(self.cause()) }
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(self.inner.failure(), f)
+    }
+}
+
+impl Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.inner.backtrace.is_none() {
+            Debug::fmt(self.inner.failure(), f)
+        } else {
+            write!(f, "{:?}\n\n{:?}", self.inner.failure(), self.inner.backtrace)
+        }
+    }
+}
+
+impl Drop for Error {
+    fn drop(&mut self) {
+        unsafe {
+            let layout = {
+                let header = Layout::new::<InnerHeader>();
+                header.extend(Layout::for_value(self.inner.failure())).unwrap().0
+            };
+            Heap.dealloc(self.inner as *const _ as *const u8 as *mut u8, layout);
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::mem::size_of;
+    use std::io;
+
+    use super::Error;
+
+    #[test]
+    fn assert_error_is_just_data() {
+        fn assert_just_data<T: Send + Sync + 'static>() { }
+        assert_just_data::<Error>();
+    }
+
+    #[test]
+    fn assert_is_one_word() {
+        assert_eq!(size_of::<Error>(), size_of::<usize>());
+    }
+
+    #[test]
+    fn methods_seem_to_work() {
+        let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test");
+        let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
+        assert!(error.downcast_ref::<io::Error>().is_some());
+        let _: ::Backtrace = *error.backtrace();
+        assert_eq!(format!("{:?}", io_error), format!("{:?}", error));
+        assert_eq!(format!("{}", io_error), format!("{}", error));
+        drop(error);
+        assert!(true);
+    }
+}
diff --git a/src/sync_failure.rs b/src/sync_failure.rs
new file mode 100644 (file)
index 0000000..63e966c
--- /dev/null
@@ -0,0 +1,97 @@
+use Fail;
+use std::error::Error;
+use std::fmt::{self, Debug, Display};
+use std::sync::Mutex;
+
+/// Wrapper for `std` errors to make them `Sync`.
+///
+/// This exists to coerce existing types that are only `Error + Send +
+/// 'static` into a `Fail`-compatible representation, most notably for
+/// types generated by `error-chain`.
+///
+/// Unfortunately, this requires wrapping the error in a `Mutex`, which must
+/// be locked for every `Debug`/`Display`. Therefore, this should be
+/// something of a last resort in making the error work with `failure`.
+///
+pub struct SyncFailure<T> {
+    inner: Mutex<T>,
+}
+
+impl<E: Error + Send + 'static> SyncFailure<E> {
+    /// Wraps a non-`Sync` `Error` in order to make it implement `Fail`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// extern crate failure;
+    ///
+    /// # use std::error::Error as StdError;
+    /// # use std::fmt::{self, Display};
+    /// use failure::{Error, SyncFailure};
+    /// use std::cell::RefCell;
+    ///
+    /// #[derive(Debug)]
+    /// struct NonSyncError {
+    ///     // RefCells are non-Sync, so structs containing them will be
+    ///     // non-Sync as well.
+    ///     count: RefCell<usize>,
+    /// }
+    ///
+    /// // implement Display/Error for NonSyncError...
+    /// #
+    /// # impl StdError for NonSyncError {
+    /// #     fn description(&self) -> &str {
+    /// #         "oops!"
+    /// #     }
+    /// # }
+    /// #
+    /// # impl Display for NonSyncError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    /// #         write!(f, "oops!")
+    /// #     }
+    /// # }
+    ///
+    /// fn returns_error() -> Result<(), NonSyncError> {
+    ///     // Do stuff
+    ///     # Ok(())
+    /// }
+    ///
+    /// fn my_function() -> Result<(), Error> {
+    ///     // without the map_err here, we end up with a compile error
+    ///     // complaining that NonSyncError doesn't implement Sync.
+    ///     returns_error().map_err(SyncFailure::new)?;
+    ///     // Do more stuff
+    ///     # Ok(())
+    /// }
+    /// #
+    /// # fn main() {
+    /// #    my_function().unwrap();
+    /// # }
+    /// ```
+    ///
+    pub fn new(err: E) -> Self {
+        SyncFailure {
+            inner: Mutex::new(err),
+        }
+    }
+}
+
+impl<T> Display for SyncFailure<T>
+where
+    T: Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.lock().unwrap().fmt(f)
+    }
+}
+
+impl<T> Debug for SyncFailure<T>
+where
+    T: Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        (*self.inner.lock().unwrap()).fmt(f)
+    }
+}
+
+impl<E: Error + Send + 'static> Fail for SyncFailure<E> {}
diff --git a/tests/basic_fail.rs b/tests/basic_fail.rs
new file mode 100644 (file)
index 0000000..574886d
--- /dev/null
@@ -0,0 +1,21 @@
+#[macro_use]
+extern crate failure;
+
+use failure::Fail;
+
+#[test]
+fn test_name() {
+    #[derive(Fail, Debug)]
+    #[fail(display = "my error")]
+    struct MyError;
+
+    let err = MyError;
+
+    assert_eq!(err.to_string(), "my error");
+    assert_eq!(err.name(), Some("basic_fail::MyError"));
+
+    let ctx = err.context("whatever");
+
+    assert_eq!(ctx.to_string(), "whatever");
+    assert_eq!(ctx.name(), Some("basic_fail::MyError"));
+}
\ No newline at end of file
diff --git a/tests/fail_compat.rs b/tests/fail_compat.rs
new file mode 100644 (file)
index 0000000..81f84be
--- /dev/null
@@ -0,0 +1,35 @@
+#[macro_use]
+extern crate failure;
+
+use failure::Fail;
+
+fn return_failure() -> Result<(), failure::Error> {
+    #[derive(Fail, Debug)]
+    #[fail(display = "my error")]
+    struct MyError;
+
+    let err = MyError;
+    Err(err.into())
+}
+
+fn return_error() -> Result<(), Box<dyn std::error::Error>> {
+    return_failure()?;
+    Ok(())
+}
+
+fn return_error_send_sync() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+    return_failure()?;
+    Ok(())
+}
+
+#[test]
+fn smoke_default_compat() {
+    let err = return_error();
+    assert!(err.is_err());
+}
+
+#[test]
+fn smoke_compat_send_sync() {
+    let err = return_error_send_sync();
+    assert!(err.is_err());
+}
diff --git a/tests/macro_trailing_comma.rs b/tests/macro_trailing_comma.rs
new file mode 100644 (file)
index 0000000..012d006
--- /dev/null
@@ -0,0 +1,67 @@
+#[macro_use]
+extern crate failure;
+
+// NOTE:
+//
+// This test is in a separate file due to the fact that ensure! cannot be used
+// from within failure.
+//
+// (you get: 'macro-expanded `macro_export` macros from the current crate cannot
+//           be referred to by absolute paths')
+
+// Encloses an early-returning macro in an IIFE so that we
+// can treat it as a Result-returning function.
+macro_rules! wrap_early_return {
+    ($expr:expr) => {{
+        fn func() -> Result<(), failure::Error> {
+            let _ = $expr;
+
+            #[allow(unreachable_code)]
+            Ok(())
+        }
+        func().map_err(|e| e.to_string())
+    }};
+}
+
+#[test]
+fn bail() {
+    assert_eq!(
+        wrap_early_return!(bail!("test")),
+        wrap_early_return!(bail!("test",)));
+    assert_eq!(
+        wrap_early_return!(bail!("test {}", 4)),
+        wrap_early_return!(bail!("test {}", 4,)));
+}
+
+#[test]
+fn ensure() {
+    assert_eq!(
+        wrap_early_return!(ensure!(false, "test")),
+        wrap_early_return!(ensure!(false, "test",)));
+    assert_eq!(
+        wrap_early_return!(ensure!(false, "test {}", 4)),
+        wrap_early_return!(ensure!(false, "test {}", 4,)));
+}
+
+#[test]
+fn single_arg_ensure() {
+    assert_eq!(
+        wrap_early_return!(ensure!(false)),
+        Err("false".to_string()));
+    assert_eq!(
+        wrap_early_return!(ensure!(true == false)),
+        Err("true == false".to_string()));
+    assert_eq!(
+        wrap_early_return!(ensure!(4 == 5)),
+        Err("4 == 5".to_string()));
+}
+
+#[test]
+fn format_err() {
+    assert_eq!(
+        format_err!("test").to_string(),
+        format_err!("test",).to_string());
+    assert_eq!(
+        format_err!("test {}", 4).to_string(),
+        format_err!("test {}", 4,).to_string());
+}
diff --git a/travis.sh b/travis.sh
new file mode 100644 (file)
index 0000000..6c621ca
--- /dev/null
+++ b/travis.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+cargo_test() {
+   cargo test "$@" || { exit 101; }
+}
+
+test_failure_in() {
+  cd $1
+  cargo_test
+  cargo_test --no-default-features
+  cargo_test --features backtrace
+  test_derive_in "$1/failure_derive"
+  cd $DIR
+}
+
+test_derive_in() {
+  cd $1
+  cargo_test
+  cd $DIR
+}
+
+test_nightly_features_in() {
+  cd $1
+  #cargo_test --features small-error
+  cargo_test --all-features
+  cd $DIR
+}
+
+main() {
+  test_failure_in "$DIR/failure-1.X"
+  test_failure_in "$DIR/failure-0.1.X"
+  if [ "${TRAVIS_RUST_VERSION}" = "nightly" ]; then
+    test_nightly_features_in "$DIR/failure-1.X"
+  fi
+}
+
+main