mirror of
https://github.com/haraldh/chainerror.git
synced 2025-01-31 09:04:14 +01:00
parent
719e221e4b
commit
5c93f1a5fe
27
editor.js
27
editor.js
|
@ -1,27 +0,0 @@
|
||||||
"use strict";
|
|
||||||
window.editors = [];
|
|
||||||
(function(editors) {
|
|
||||||
if (typeof(ace) === 'undefined' || !ace) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array.from(document.querySelectorAll('.editable')).forEach(function(editable) {
|
|
||||||
let editor = ace.edit(editable);
|
|
||||||
editor.setOptions({
|
|
||||||
highlightActiveLine: false,
|
|
||||||
showPrintMargin: false,
|
|
||||||
showLineNumbers: false,
|
|
||||||
showGutter: false,
|
|
||||||
maxLines: Infinity,
|
|
||||||
fontSize: "0.875em" // please adjust the font size of the code in general.styl
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.$blockScrolling = Infinity;
|
|
||||||
|
|
||||||
editor.getSession().setMode("ace/mode/rust");
|
|
||||||
|
|
||||||
editor.originalCode = editor.getValue();
|
|
||||||
|
|
||||||
editors.push(editor);
|
|
||||||
});
|
|
||||||
})(window.editors);
|
|
198
end.html
Normal file
198
end.html
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>The End - chainerror</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body class="light">
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
document.body.className = theme;
|
||||||
|
document.querySelector('html').className = theme + ' js';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html" class="active">The End</a></li></ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar" class="menu-bar">
|
||||||
|
<div id="menu-bar-sticky-container">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">chainerror</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<a class="header" href="#the-end" id="the-end"><h1>The End</h1></a>
|
||||||
|
<p>That's it for now…</p>
|
||||||
|
<p>Happy error handling!</p>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="tutorial11.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a href="tutorial11.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
129
index.html
129
index.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 1 - chainerror</title>
|
<title>chainerror - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -140,37 +140,116 @@
|
||||||
|
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#simple-string-errors" id="simple-string-errors"><h1>Simple String Errors</h1></a>
|
<a class="header" href="#chainerror" id="chainerror"><h1>chainerror</h1></a>
|
||||||
<p>The most simplest of doing error handling in rust is by returning <code>String</code> as a <code>Box<Error></code>.</p>
|
<p><code>chainerror</code> provides an error backtrace like <code>failure</code> without doing a real backtrace, so even after you <code>strip</code> your
|
||||||
<p>As you can see by running the example (the "Play" button in upper right of the code block), this only
|
binaries, you still have the error backtrace.</p>
|
||||||
prints out the last <code>Error</code>.</p>
|
<p><code>chainerror</code> has no dependencies!</p>
|
||||||
<p>If the rust <code>main</code> function returns an Err(), this Err() will be displayed with <code>std::fmt::Debug</code>.</p>
|
<p><code>chainerror</code> uses <code>.source()</code> of <code>std::error::Error</code> along with <code>line()!</code> and <code>file()!</code> to provide a nice debug error backtrace.
|
||||||
<pre><pre class="playpen"><code class="language-rust">use std::error::Error;
|
It encapsulates all types, which have <code>Display + Debug</code> and can store the error cause internally.</p>
|
||||||
|
<p>Along with the <code>ChainError<T></code> struct, <code>chainerror</code> comes with some useful helper macros to save a lot of typing.</p>
|
||||||
|
<p>Debug information is worth it!</p>
|
||||||
|
<p>Now continue reading the
|
||||||
|
<a href="https://haraldh.github.io/chainerror/tutorial1.html">Tutorial</a></p>
|
||||||
|
<a class="header" href="#example" id="example"><h2>Example:</h2></a>
|
||||||
|
<p>Output:</p>
|
||||||
|
<pre><code>$ cargo run -q --example example
|
||||||
|
Main Error Report: func1 error calling func2
|
||||||
|
|
||||||
|
Error reported by Func2Error: func2 error: calling func3
|
||||||
|
|
||||||
|
The root cause was: std::io::Error: Kind(
|
||||||
|
NotFound
|
||||||
|
)
|
||||||
|
|
||||||
|
Debug Error:
|
||||||
|
examples/example.rs:45: func1 error calling func2
|
||||||
|
Caused by:
|
||||||
|
examples/example.rs:20: Func2Error(func2 error: calling func3)
|
||||||
|
Caused by:
|
||||||
|
examples/example.rs:13: Error reading 'foo.txt'
|
||||||
|
Caused by:
|
||||||
|
Kind(NotFound)
|
||||||
|
</code></pre>
|
||||||
|
<pre><code class="language-rust ignore">use chainerror::*;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
fn do_some_io() -> Result<(), Box<Error>> {
|
fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
Err("do_some_io error")?;
|
Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func2() -> Result<(), Box<Error>> {
|
fn func3() -> Result<(), Box<Error>> {
|
||||||
if let Err(_) = do_some_io() {
|
let filename = "foo.txt";
|
||||||
Err("func2 error")?;
|
do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_str_cherr!(Func2Error);
|
||||||
|
|
||||||
|
fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Func1Error {
|
||||||
|
Func2,
|
||||||
|
IO(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for Func1Error {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn func1() -> Result<(), Box<Error>> {
|
|
||||||
if let Err(_) = func2() {
|
|
||||||
Err("func1 error")?;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Debug for Func1Error {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
let filename = String::from("bar.txt");
|
||||||
|
do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<Error>> {
|
fn main() {
|
||||||
func1()
|
if let Err(e) = func1() {
|
||||||
|
match e.kind() {
|
||||||
|
Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
|
||||||
|
Func1Error::IO(filename) => {
|
||||||
|
eprintln!("Main Error Report: func1 error reading '{}'", filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(e) = e.root_cause() {
|
||||||
|
let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("\nDebug Error:\n{:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</code></pre></pre>
|
|
||||||
|
</code></pre>
|
||||||
|
<a class="header" href="#features" id="features"><h2>Features</h2></a>
|
||||||
|
<p><code>no-fileline</code>
|
||||||
|
: completely turn off storing filename and line</p>
|
||||||
|
<p><code>display-cause</code>
|
||||||
|
: turn on printing a backtrace of the errors in <code>Display</code></p>
|
||||||
|
<p><code>no-debug-cause</code>
|
||||||
|
: turn off printing a backtrace of the errors in <code>Debug</code></p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -198,12 +277,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
File diff suppressed because one or more lines are too long
5672
print.html
5672
print.html
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
||||||
ace.define("ace/theme/dawn",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-dawn",t.cssText=".ace-dawn .ace_gutter {background: #ebebeb;color: #333}.ace-dawn .ace_print-margin {width: 1px;background: #e8e8e8}.ace-dawn {background-color: #F9F9F9;color: #080808}.ace-dawn .ace_cursor {color: #000000}.ace-dawn .ace_marker-layer .ace_selection {background: rgba(39, 95, 255, 0.30)}.ace-dawn.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #F9F9F9;}.ace-dawn .ace_marker-layer .ace_step {background: rgb(255, 255, 0)}.ace-dawn .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(75, 75, 126, 0.50)}.ace-dawn .ace_marker-layer .ace_active-line {background: rgba(36, 99, 180, 0.12)}.ace-dawn .ace_gutter-active-line {background-color : #dcdcdc}.ace-dawn .ace_marker-layer .ace_selected-word {border: 1px solid rgba(39, 95, 255, 0.30)}.ace-dawn .ace_invisible {color: rgba(75, 75, 126, 0.50)}.ace-dawn .ace_keyword,.ace-dawn .ace_meta {color: #794938}.ace-dawn .ace_constant,.ace-dawn .ace_constant.ace_character,.ace-dawn .ace_constant.ace_character.ace_escape,.ace-dawn .ace_constant.ace_other {color: #811F24}.ace-dawn .ace_invalid.ace_illegal {text-decoration: underline;font-style: italic;color: #F8F8F8;background-color: #B52A1D}.ace-dawn .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #B52A1D}.ace-dawn .ace_support {color: #691C97}.ace-dawn .ace_support.ace_constant {color: #B4371F}.ace-dawn .ace_fold {background-color: #794938;border-color: #080808}.ace-dawn .ace_list,.ace-dawn .ace_markup.ace_list,.ace-dawn .ace_support.ace_function {color: #693A17}.ace-dawn .ace_storage {font-style: italic;color: #A71D5D}.ace-dawn .ace_string {color: #0B6125}.ace-dawn .ace_string.ace_regexp {color: #CF5628}.ace-dawn .ace_comment {font-style: italic;color: #5A525F}.ace-dawn .ace_heading,.ace-dawn .ace_markup.ace_heading {color: #19356D}.ace-dawn .ace_variable {color: #234A97}.ace-dawn .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
|
|
|
@ -1 +0,0 @@
|
||||||
ace.define("ace/theme/tomorrow_night",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-tomorrow-night",t.cssText=".ace-tomorrow-night .ace_gutter {background: #25282c;color: #C5C8C6}.ace-tomorrow-night .ace_print-margin {width: 1px;background: #25282c}.ace-tomorrow-night {background-color: #1D1F21;color: #C5C8C6}.ace-tomorrow-night .ace_cursor {color: #AEAFAD}.ace-tomorrow-night .ace_marker-layer .ace_selection {background: #373B41}.ace-tomorrow-night.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #1D1F21;}.ace-tomorrow-night .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-tomorrow-night .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #4B4E55}.ace-tomorrow-night .ace_marker-layer .ace_active-line {background: #282A2E}.ace-tomorrow-night .ace_gutter-active-line {background-color: #282A2E}.ace-tomorrow-night .ace_marker-layer .ace_selected-word {border: 1px solid #373B41}.ace-tomorrow-night .ace_invisible {color: #4B4E55}.ace-tomorrow-night .ace_keyword,.ace-tomorrow-night .ace_meta,.ace-tomorrow-night .ace_storage,.ace-tomorrow-night .ace_storage.ace_type,.ace-tomorrow-night .ace_support.ace_type {color: #B294BB}.ace-tomorrow-night .ace_keyword.ace_operator {color: #8ABEB7}.ace-tomorrow-night .ace_constant.ace_character,.ace-tomorrow-night .ace_constant.ace_language,.ace-tomorrow-night .ace_constant.ace_numeric,.ace-tomorrow-night .ace_keyword.ace_other.ace_unit,.ace-tomorrow-night .ace_support.ace_constant,.ace-tomorrow-night .ace_variable.ace_parameter {color: #DE935F}.ace-tomorrow-night .ace_constant.ace_other {color: #CED1CF}.ace-tomorrow-night .ace_invalid {color: #CED2CF;background-color: #DF5F5F}.ace-tomorrow-night .ace_invalid.ace_deprecated {color: #CED2CF;background-color: #B798BF}.ace-tomorrow-night .ace_fold {background-color: #81A2BE;border-color: #C5C8C6}.ace-tomorrow-night .ace_entity.ace_name.ace_function,.ace-tomorrow-night .ace_support.ace_function,.ace-tomorrow-night .ace_variable {color: #81A2BE}.ace-tomorrow-night .ace_support.ace_class,.ace-tomorrow-night .ace_support.ace_type {color: #F0C674}.ace-tomorrow-night .ace_heading,.ace-tomorrow-night .ace_markup.ace_heading,.ace-tomorrow-night .ace_string {color: #B5BD68}.ace-tomorrow-night .ace_entity.ace_name.ace_tag,.ace-tomorrow-night .ace_entity.ace_other.ace_attribute-name,.ace-tomorrow-night .ace_meta.ace_tag,.ace-tomorrow-night .ace_string.ace_regexp,.ace-tomorrow-night .ace_variable {color: #CC6666}.ace-tomorrow-night .ace_comment {color: #969896}.ace-tomorrow-night .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
|
|
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 1 - chainerror</title>
|
<title>Simple String Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html" class="active"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html" class="active"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,15 +141,25 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#simple-string-errors" id="simple-string-errors"><h1>Simple String Errors</h1></a>
|
<a class="header" href="#simple-string-errors" id="simple-string-errors"><h1>Simple String Errors</h1></a>
|
||||||
<p>The most simplest of doing error handling in rust is by returning <code>String</code> as a <code>Box<Error></code>.</p>
|
<p>An easy way of doing error handling in rust is by returning <code>String</code> as a <code>Box<std::error::Error></code>.</p>
|
||||||
<p>As you can see by running the example (the "Play" button in upper right of the code block), this only
|
<p>If the rust <code>main</code> function returns an <code>Err()</code>, this <code>Err()</code> will be displayed with <code>std::fmt::Debug</code>.</p>
|
||||||
|
<p>As you can see by running the example (by pressing the "Play" button in upper right of the code block),
|
||||||
|
this only
|
||||||
prints out the last <code>Error</code>.</p>
|
prints out the last <code>Error</code>.</p>
|
||||||
<p>If the rust <code>main</code> function returns an Err(), this Err() will be displayed with <code>std::fmt::Debug</code>.</p>
|
<pre><code>Error: StringError("func1 error")
|
||||||
|
</code></pre>
|
||||||
|
<p>The next chapters of this tutorial show how <code>chainerror</code> adds more information
|
||||||
|
and improves inspecting the sources of an error.</p>
|
||||||
|
<p>You can also run the tutorial examples in the checked out
|
||||||
|
<a href="https://github.com/haraldh/chainerror">chainerror git repo</a>.</p>
|
||||||
|
<pre><code>$ cargo run -q --example tutorial1
|
||||||
|
</code></pre>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use std::error::Error;
|
<pre><pre class="playpen"><code class="language-rust">use std::error::Error;
|
||||||
|
use std::io;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
fn do_some_io() -> Result<(), Box<Error>> {
|
fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
Err("do_some_io error")?;
|
Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +180,7 @@ fn func1() -> Result<(), Box<Error>> {
|
||||||
fn main() -> Result<(), Box<Error>> {
|
fn main() -> Result<(), Box<Error>> {
|
||||||
func1()
|
func1()
|
||||||
}
|
}
|
||||||
|
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
@ -177,6 +188,10 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
<!-- Mobile navigation buttons -->
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a rel="next" href="tutorial2.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
<a rel="next" href="tutorial2.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
@ -191,6 +206,10 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a href="index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="tutorial2.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
<a href="tutorial2.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
@ -206,12 +225,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
580
tutorial10.html
580
tutorial10.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 10 - chainerror</title>
|
<title>ErrorKind to the rescue - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html" class="active"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html" class="active"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,16 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#errorkind-to-the-rescue" id="errorkind-to-the-rescue"><h1>ErrorKind to the rescue</h1></a>
|
<a class="header" href="#errorkind-to-the-rescue" id="errorkind-to-the-rescue"><h1>ErrorKind to the rescue</h1></a>
|
||||||
<p>[TBD]</p>
|
<p>To cope with different kind of errors, we introduce the kind of an error <code>Func1ErrorKind</code> with an enum.</p>
|
||||||
|
<p>Because we derive <code>Debug</code> and implement <code>Display</code> our <code>Func1ErrorKind</code> enum, this enum can be used as
|
||||||
|
a <code>std::error::Error</code>.</p>
|
||||||
|
<p>Not using <code>String</code> errors anymore, the <code>cherr!()</code> macro seen in the beginning of
|
||||||
|
the tutorial has to be used again.</p>
|
||||||
|
<p>Only returning <code>Func1ErrorKind</code> in <code>func1()</code> now let us get rid of <code>Result<(), Box<Error>></code> and we can
|
||||||
|
use <code>ChainResult<(), Func1ErrorKind></code>.</p>
|
||||||
|
<p>In <code>main</code> we can now directly use the methods of <code>ChainError<T></code> without downcasting the error first.</p>
|
||||||
|
<p>Also a nice <code>match</code> on <code>ChainError<T>.kind()</code> is now possible, which returns <code>&T</code>, meaning
|
||||||
|
<code>&Func1ErrorKind</code> here.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -161,38 +170,38 @@ fn func2() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Func1Error {
|
enum Func1ErrorKind {
|
||||||
Func2,
|
Func2,
|
||||||
IO(String),
|
IO(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for Func1Error {
|
impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func1() -> ChainResult<(), Func1Error> {
|
fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
let filename = String::from("bar.txt");
|
let filename = String::from("bar.txt");
|
||||||
do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO(filename)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<Error>> {
|
fn main() -> Result<(), Box<Error>> {
|
||||||
if let Err(e) = func1() {
|
if let Err(e) = func1() {
|
||||||
match e.kind() {
|
match e.kind() {
|
||||||
Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
|
Func1ErrorKind::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
|
||||||
Func1Error::IO(filename) => {
|
Func1ErrorKind::IO(filename) => {
|
||||||
eprintln!("Main Error Report: func1 error reading '{}'", filename)
|
eprintln!("Main Error Report: func1 error reading '{}'", filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
eprintln!("Error reported by Func2Error: {}", e)
|
eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("\nDebug Error:\n{:?}", e);
|
eprintln!("\nDebug Error:\n{:?}", e);
|
||||||
|
@ -201,10 +210,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -212,10 +378,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -229,6 +397,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -237,6 +406,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -245,6 +415,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -259,6 +477,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -273,19 +506,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -404,7 +702,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -417,6 +719,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -427,6 +816,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -440,6 +915,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -457,26 +975,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -522,12 +1020,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
592
tutorial11.html
592
tutorial11.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 11 - chainerror</title>
|
<title>Debug for the ErrorKind - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html" class="active"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html" class="active"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,18 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#debug-for-the-errorkind" id="debug-for-the-errorkind"><h1>Debug for the ErrorKind</h1></a>
|
<a class="header" href="#debug-for-the-errorkind" id="debug-for-the-errorkind"><h1>Debug for the ErrorKind</h1></a>
|
||||||
<p>[TBD]</p>
|
<p>One small improvement at the end of the tutorial is to fix the debug output of
|
||||||
|
<code>Func1ErrorKind</code>. As you probably noticed, the output doesn't say much of the enum.</p>
|
||||||
|
<pre><code>Debug Error:
|
||||||
|
src/main.rs:35: Func2
|
||||||
|
[…]
|
||||||
|
</code></pre>
|
||||||
|
<p>As a lazy shortcut, we implement <code>Debug</code> by calling <code>Display</code> and end up with</p>
|
||||||
|
<pre><code>Debug Error:
|
||||||
|
src/main.rs:40: func1 error calling func2
|
||||||
|
[…}
|
||||||
|
</code></pre>
|
||||||
|
<p>which gives us a lot more detail.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -160,44 +171,44 @@ fn func2() -> Result<(), Box<Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Func1Error {
|
enum Func1ErrorKind {
|
||||||
Func2,
|
Func2,
|
||||||
IO(String),
|
IO(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for Func1Error {
|
impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Debug for Func1Error {
|
impl ::std::fmt::Debug for Func1ErrorKind {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
write!(f, "{}", self)
|
write!(f, "{}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func1() -> ChainResult<(), Func1Error> {
|
fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
let filename = String::from("bar.txt");
|
let filename = String::from("bar.txt");
|
||||||
do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO(filename)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<Error>> {
|
fn main() -> Result<(), Box<Error>> {
|
||||||
if let Err(e) = func1() {
|
if let Err(e) = func1() {
|
||||||
match e.kind() {
|
match e.kind() {
|
||||||
Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
|
Func1ErrorKind::Func2 => eprintln!("Main Error Report: func1 error calling func2"),
|
||||||
Func1Error::IO(filename) => {
|
Func1ErrorKind::IO(filename) => {
|
||||||
eprintln!("Main Error Report: func1 error reading '{}'", filename)
|
eprintln!("Main Error Report: func1 error reading '{}'", filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
eprintln!("Error reported by Func2Error: {}", e)
|
eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("\nDebug Error:\n{:?}", e);
|
eprintln!("\nDebug Error:\n{:?}", e);
|
||||||
|
@ -206,10 +217,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -217,10 +385,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -234,6 +404,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -242,6 +413,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -250,6 +422,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -264,6 +484,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -278,19 +513,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -409,7 +709,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -422,6 +726,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -432,6 +823,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -445,6 +922,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -462,26 +982,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -496,6 +996,10 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="end.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
<div style="clear: both"></div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -510,6 +1014,10 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a href="end.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -519,12 +1027,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
565
tutorial2.html
565
tutorial2.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 2 - chainerror</title>
|
<title>Simple Chained String Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html" class="active"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html" class="active"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,14 +141,17 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#simple-chained-string-errors" id="simple-chained-string-errors"><h1>Simple Chained String Errors</h1></a>
|
<a class="header" href="#simple-chained-string-errors" id="simple-chained-string-errors"><h1>Simple Chained String Errors</h1></a>
|
||||||
<p>Now with the help of the <code>chainerror</code> crate, we can have a nicer output.</p>
|
<p>With relatively small changes and the help of the <code>cherr!</code> macro of the <code>chainerror</code> crate
|
||||||
|
the <code>String</code> errors are now chained together.</p>
|
||||||
<p>Press the play button in the upper right corner and see the nice debug output.</p>
|
<p>Press the play button in the upper right corner and see the nice debug output.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
fn do_some_io() -> Result<(), Box<Error>> {
|
fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
Err("do_some_io error")?;
|
Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,10 +174,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -182,10 +342,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -199,6 +361,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -207,6 +370,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -215,6 +379,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -229,6 +441,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -243,19 +470,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -374,7 +666,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -387,6 +683,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -397,6 +780,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -410,6 +879,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -427,26 +939,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<a class="header" href="#what-did-we-do-here" id="what-did-we-do-here"><h3>What did we do here?</h3></a>
|
<a class="header" href="#what-did-we-do-here" id="what-did-we-do-here"><h3>What did we do here?</h3></a>
|
||||||
|
@ -454,13 +946,14 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
Err(cherr!(e, "func2 error"))?;
|
Err(cherr!(e, "func2 error"))?;
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>The macro <code>cherr!(cause, newerror)</code> stores <code>cause</code> as the source/cause of <code>newerror</code> and returns
|
<p>The macro <code>cherr!(olderror, newerror)</code> stores <code>olderror</code> as the source/cause of <code>newerror</code>
|
||||||
<code>newerror</code>, along with the filename (<code>file!()</code>) and line number (<code>line!()</code>).</p>
|
along with the filename (<code>file!()</code>) and line number (<code>line!()</code>)
|
||||||
<p><code>Err(e)?</code> then returns the error <code>e</code> applying <code>e.into()</code>, so that we
|
and returns <code>newerror</code>.</p>
|
||||||
|
<p><code>Err()?</code> then returns the inner error applying <code>.into()</code>, so that we
|
||||||
again have a <code>Err(Box<Error>)</code> as a result.</p>
|
again have a <code>Err(Box<Error>)</code> as a result.</p>
|
||||||
<p>The <code>Debug</code> implementation of <code>ChainError<T></code> (which is returned by <code>cherr!()</code>)
|
<p>The <code>Debug</code> implementation of <code>ChainError<T></code> (which is returned by <code>cherr!()</code>)
|
||||||
prints the <code>Debug</code> of <code>T</code> prefixed with the stored filename and line number.</p>
|
prints the <code>Debug</code> of <code>T</code> prefixed with the stored filename and line number.</p>
|
||||||
<p><code>ChainError<T></code> is in our case <code>ChainError<String></code>.</p>
|
<p><code>ChainError<T></code> in our case is <code>ChainError<String></code>.</p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -504,12 +997,6 @@ prints the <code>Debug</code> of <code>T</code> prefixed with the stored filenam
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
553
tutorial3.html
553
tutorial3.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 3 - chainerror</title>
|
<title>Mapping Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html" class="active"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html" class="active"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -143,11 +143,13 @@
|
||||||
<a class="header" href="#mapping-errors" id="mapping-errors"><h1>Mapping Errors</h1></a>
|
<a class="header" href="#mapping-errors" id="mapping-errors"><h1>Mapping Errors</h1></a>
|
||||||
<p>Now let's get more rust idiomatic by using <code>.map_err()</code>.</p>
|
<p>Now let's get more rust idiomatic by using <code>.map_err()</code>.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
fn do_some_io() -> Result<(), Box<Error>> {
|
fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
Err("do_some_io error")?;
|
Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +171,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -180,10 +339,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -197,6 +358,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -205,6 +367,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -213,6 +376,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -227,6 +438,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -241,19 +467,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -372,7 +663,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -385,6 +680,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -395,6 +777,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -408,6 +876,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -425,26 +936,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>If you compare the output to the previous example, you will see,
|
<p>If you compare the output to the previous example, you will see,
|
||||||
|
@ -500,12 +991,6 @@ Maybe depending on <code>--debug</code> as a CLI argument.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
552
tutorial4.html
552
tutorial4.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 4 - chainerror</title>
|
<title>Saving coding chars - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html" class="active"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html" class="active"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -148,10 +148,11 @@ more debug strings.</p>
|
||||||
<p><code>mstrerror!()</code> even understands <code>format!()</code> syntax like <code>println!()</code>.</p>
|
<p><code>mstrerror!()</code> even understands <code>format!()</code> syntax like <code>println!()</code>.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
fn do_some_io() -> Result<(), Box<Error>> {
|
fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
Err("do_some_io error")?;
|
Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +175,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -185,10 +343,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -202,6 +362,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -210,6 +371,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -218,6 +380,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -232,6 +442,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -246,19 +471,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -377,7 +667,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -390,6 +684,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -400,6 +781,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -413,6 +880,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -430,26 +940,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -495,12 +985,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
553
tutorial5.html
553
tutorial5.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 5 - chainerror</title>
|
<title>The source() of Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html" class="active"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html" class="active"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -177,10 +177,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -188,10 +345,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -205,6 +364,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -213,6 +373,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -221,6 +382,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -235,6 +444,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -249,19 +473,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -380,7 +669,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -393,6 +686,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -403,6 +783,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -416,6 +882,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -433,30 +942,10 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>Note, that we changed the output of the error in <code>main()</code> from <code>Debug</code> to <code>Display</code>, so we don't see
|
<p>Note, that because we changed the output of the error in <code>main()</code> from
|
||||||
the error backtrace with filename and line number.</p>
|
<code>Debug</code> to <code>Display</code>, we don't see the error backtrace with filename and line number.</p>
|
||||||
<p>To enable the <code>Display</code> backtrace, you have to enable the feature <code>display-cause</code> for <code>chainerror</code>.</p>
|
<p>To enable the <code>Display</code> backtrace, you have to enable the feature <code>display-cause</code> for <code>chainerror</code>.</p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
@ -501,12 +990,6 @@ the error backtrace with filename and line number.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
556
tutorial6.html
556
tutorial6.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 6 - chainerror</title>
|
<title>Downcast the Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html" class="active"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html" class="active"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,12 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#downcast-the-errors" id="downcast-the-errors"><h1>Downcast the Errors</h1></a>
|
<a class="header" href="#downcast-the-errors" id="downcast-the-errors"><h1>Downcast the Errors</h1></a>
|
||||||
<p>[TBD]</p>
|
<p><code>std::error::Error</code> comes with some helper methods to get to the original object of the
|
||||||
|
<code>&(dyn Error + 'static)</code> returned by <code>.source()</code>.</p>
|
||||||
|
<pre><code class="language-rust ignore">pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T>
|
||||||
|
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T>
|
||||||
|
</code></pre>
|
||||||
|
<p>This is how it looks like, when using those:</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -184,10 +189,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -195,10 +357,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -212,6 +376,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -220,6 +385,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -228,6 +394,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -242,6 +456,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -256,19 +485,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -387,7 +681,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -400,6 +698,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -410,6 +795,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -423,6 +894,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -440,26 +954,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -505,12 +999,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
567
tutorial7.html
567
tutorial7.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 7 - chainerror</title>
|
<title>The root cause of all Errors - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html" class="active"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html" class="active"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,23 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#the-root-cause-of-all-errors" id="the-root-cause-of-all-errors"><h1>The root cause of all Errors</h1></a>
|
<a class="header" href="#the-root-cause-of-all-errors" id="the-root-cause-of-all-errors"><h1>The root cause of all Errors</h1></a>
|
||||||
<p>[TBD]</p>
|
<p><code>chainerror</code> also has some helper methods:</p>
|
||||||
|
<pre><code class="language-rust ignore">fn is_chain<T: 'static + Display + Debug>(&self) -> bool
|
||||||
|
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>
|
||||||
|
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>
|
||||||
|
fn root_cause(&self) -> Option<&(dyn Error + 'static)>
|
||||||
|
fn find_cause<U: Error + 'static>(&self) -> Option<&U>
|
||||||
|
fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>>
|
||||||
|
fn kind<'a>(&'a self) -> &'a T
|
||||||
|
</code></pre>
|
||||||
|
<p>Using <code>downcast_chain_ref::<String>()</code> gives a <code>ChainError<String></code>, which can be used
|
||||||
|
to call <code>.find_cause::<io::Error>()</code>.</p>
|
||||||
|
<pre><code class="language-rust ignore"> if let Some(s) = e.downcast_chain_ref::<String>() {
|
||||||
|
if let Some(ioerror) = s.find_cause::<io::Error>() {
|
||||||
|
</code></pre>
|
||||||
|
<p>or to use <code>.root_cause()</code>, which of course can be of any type implementing <code>std::error::Error</code>.</p>
|
||||||
|
<pre><code class="language-rust ignore"> if let Some(e) = s.root_cause() {
|
||||||
|
</code></pre>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -185,10 +201,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -196,10 +369,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -213,6 +388,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -221,6 +397,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -229,6 +406,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -243,6 +468,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -257,19 +497,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -388,7 +693,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -401,6 +710,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -411,6 +807,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -424,6 +906,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -441,26 +966,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -506,12 +1011,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
564
tutorial8.html
564
tutorial8.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 8 - chainerror</title>
|
<title>Finding an Error cause - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html" class="active"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html" class="active"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,20 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#finding-an-error-cause" id="finding-an-error-cause"><h1>Finding an Error cause</h1></a>
|
<a class="header" href="#finding-an-error-cause" id="finding-an-error-cause"><h1>Finding an Error cause</h1></a>
|
||||||
<p>[TBD]</p>
|
<p>To distinguish the errors occuring in various places, we can define named string errors with the
|
||||||
|
"new type" pattern.</p>
|
||||||
|
<pre><code class="language-rust ignore">derive_str_cherr!(Func2Error);
|
||||||
|
derive_str_cherr!(Func1Error);
|
||||||
|
</code></pre>
|
||||||
|
<p>Instead of <code>ChainError<String></code> we now have <code>struct Func1Error(String)</code> and <code>ChainError<Func1Error></code>.</p>
|
||||||
|
<p>In the <code>main</code> function you can see, how we can match the different errors.</p>
|
||||||
|
<p>Also see:</p>
|
||||||
|
<pre><code class="language-rust ignore"> if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() {
|
||||||
|
</code></pre>
|
||||||
|
<p>as a shortcut to</p>
|
||||||
|
<pre><code class="language-rust ignore"> if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() {
|
||||||
|
</code></pre>
|
||||||
|
<p>hiding the <code>ChainError<T></code> implementation detail.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -185,10 +198,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -196,10 +366,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -213,6 +385,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -221,6 +394,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -229,6 +403,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -243,6 +465,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -257,19 +494,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -388,7 +690,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -401,6 +707,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -411,6 +804,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -424,6 +903,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -441,26 +963,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -506,12 +1008,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
570
tutorial9.html
570
tutorial9.html
|
@ -3,9 +3,9 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Chapter 9 - chainerror</title>
|
<title>Selective Error Handling - chainerror</title>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="A tutorial for the chainerror rust crate.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
<ol class="chapter"><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Chapter 1</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Chapter 2</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Chapter 3</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Chapter 4</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> Chapter 5</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Chapter 6</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> Chapter 7</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Chapter 8</a></li><li><a href="tutorial9.html" class="active"><strong aria-hidden="true">9.</strong> Chapter 9</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> Chapter 10</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Chapter 11</a></li></ol>
|
<ol class="chapter"><li class="affix"><a href="index.html">chainerror</a></li><li><a href="tutorial1.html"><strong aria-hidden="true">1.</strong> Simple String Errors</a></li><li><a href="tutorial2.html"><strong aria-hidden="true">2.</strong> Simple Chained String Errors</a></li><li><a href="tutorial3.html"><strong aria-hidden="true">3.</strong> Mapping Errors</a></li><li><a href="tutorial4.html"><strong aria-hidden="true">4.</strong> Saving coding chars</a></li><li><a href="tutorial5.html"><strong aria-hidden="true">5.</strong> The source() of Errors</a></li><li><a href="tutorial6.html"><strong aria-hidden="true">6.</strong> Downcast the Errors</a></li><li><a href="tutorial7.html"><strong aria-hidden="true">7.</strong> The root cause of all Errors</a></li><li><a href="tutorial8.html"><strong aria-hidden="true">8.</strong> Finding an Error cause</a></li><li><a href="tutorial9.html" class="active"><strong aria-hidden="true">9.</strong> Selective Error Handling</a></li><li><a href="tutorial10.html"><strong aria-hidden="true">10.</strong> ErrorKind to the rescue</a></li><li><a href="tutorial11.html"><strong aria-hidden="true">11.</strong> Debug for the ErrorKind</a></li><li class="affix"><a href="end.html">The End</a></li></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
@ -141,7 +141,24 @@
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<main>
|
<main>
|
||||||
<a class="header" href="#selective-error-handling" id="selective-error-handling"><h1>Selective Error Handling</h1></a>
|
<a class="header" href="#selective-error-handling" id="selective-error-handling"><h1>Selective Error Handling</h1></a>
|
||||||
<p>[TBD]</p>
|
<p>What about functions returning different Error types?</p>
|
||||||
|
<p>In this example <code>func1()</code> can return either <code>Func1ErrorFunc2</code> or <code>Func1ErrorIO</code>.</p>
|
||||||
|
<p>We might want to <code>match</code> on <code>func1()</code> with something like:</p>
|
||||||
|
<pre><code class="language-rust ignore">fn main() -> Result<(), Box<Error>> {
|
||||||
|
match func1() {
|
||||||
|
Err(e) if let Some(s) = e.downcast_chain_ref::<Func1ErrorIO>() =>
|
||||||
|
eprintln!("Func1ErrorIO:\n{:?}", s),
|
||||||
|
|
||||||
|
Err(e) if let Some(s) = e.downcast_chain_ref::<Func1ErrorFunc2>() =>
|
||||||
|
eprintln!("Func1ErrorFunc2:\n{:?}", s),
|
||||||
|
|
||||||
|
Ok(_) => {},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<p>but this is not valid rust code, so we end up doing it the hard way.
|
||||||
|
In the next chapter, we will see, how to solve this more elegantly.</p>
|
||||||
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
<pre><pre class="playpen"><code class="language-rust">use crate::chainerror::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -176,7 +193,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
eprintln!("Func1ErrorIO:\n{:?}", s);
|
eprintln!("Func1ErrorIO:\n{:?}", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = try_cherr_ref!(e, Func1ErrorFunc2) {
|
if let Some(s) = e.downcast_chain_ref::<Func1ErrorFunc2>() {
|
||||||
eprintln!("Func1ErrorFunc2:\n{:?}", s);
|
eprintln!("Func1ErrorFunc2:\n{:?}", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,10 +201,167 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
}
|
}
|
||||||
# #[allow(dead_code)]
|
# #[allow(dead_code)]
|
||||||
# mod chainerror {
|
# mod chainerror {
|
||||||
|
# /*!
|
||||||
|
#
|
||||||
|
# `chainerror` provides an error backtrace without doing a real backtrace, so even after you `strip` your
|
||||||
|
# binaries, you still have the error backtrace.
|
||||||
|
#
|
||||||
|
# `chainerror` has no dependencies!
|
||||||
|
#
|
||||||
|
# `chainerror` uses `.source()` of `std::error::Error` along with `line()!` and `file()!` to provide a nice debug error backtrace.
|
||||||
|
# It encapsulates all types, which have `Display + Debug` and can store the error cause internally.
|
||||||
|
#
|
||||||
|
# Along with the `ChainError<T>` struct, `chainerror` comes with some useful helper macros to save a lot of typing.
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:20: func1 error
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# use chainerror::*;
|
||||||
|
# use std::error::Error;
|
||||||
|
# use std::io;
|
||||||
|
# use std::result::Result;
|
||||||
|
#
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func3() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# func3().map_err(mstrerr!(Func2Error, "func2 error: calling func3"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# enum Func1Error {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Display for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# match self {
|
||||||
|
# Func1Error::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# impl ::std::fmt::Debug for Func1Error {
|
||||||
|
# fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# write!(f, "{}", self)
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1Error> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1Error::Func2))?;
|
||||||
|
# let filename = String::from("bar.txt");
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# assert!(
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1Error::Func2 => {
|
||||||
|
# eprintln!("Main Error Report: func1 error calling func2");
|
||||||
|
# true
|
||||||
|
# }
|
||||||
|
# Func1Error::IO(filename) => {
|
||||||
|
# eprintln!("Main Error Report: func1 error reading '{}'", filename);
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
#
|
||||||
|
# assert!(e.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.find_chain_cause::<Func2Error>() {
|
||||||
|
# eprintln!("\nError reported by Func2Error: {}", e)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# assert!(e.root_cause().is_some());
|
||||||
|
#
|
||||||
|
# if let Some(e) = e.root_cause() {
|
||||||
|
# let ioerror = e.downcast_ref::<io::Error>().unwrap();
|
||||||
|
# eprintln!("\nThe root cause was: std::io::Error: {:#?}", ioerror);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# assert_eq!(
|
||||||
|
# format!("\n{:?}\n", e), r#"
|
||||||
|
# src/lib.rs:47: func1 error calling func2
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:22: Func2Error(func2 error: calling func3)
|
||||||
|
# Caused by:
|
||||||
|
# src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# Caused by:
|
||||||
|
# Kind(NotFound)
|
||||||
|
# "#
|
||||||
|
# );
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# !*/
|
||||||
|
#
|
||||||
|
# use std::any::TypeId;
|
||||||
# use std::error::Error;
|
# use std::error::Error;
|
||||||
# use std::fmt::{Debug, Display, Formatter, Result};
|
# use std::fmt::{Debug, Display, Formatter, Result};
|
||||||
# use std::result::Result as StdResult;
|
|
||||||
#
|
#
|
||||||
|
# /** chains an inner error kind `T` with a causing error
|
||||||
|
# **/
|
||||||
# pub struct ChainError<T> {
|
# pub struct ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
# occurrence: Option<(u32, &'static str)>,
|
# occurrence: Option<(u32, &'static str)>,
|
||||||
|
@ -195,10 +369,12 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
|
# /// convenience type alias
|
||||||
|
# pub type ChainResult<O, E> = std::result::Result<O, ChainError<E>>;
|
||||||
#
|
#
|
||||||
# impl<T: 'static + Display + Debug> ChainError<T> {
|
# impl<T: 'static + Display + Debug> ChainError<T> {
|
||||||
# #[cfg(not(feature = "no-fileline"))]
|
# #[cfg(not(feature = "no-fileline"))]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -212,6 +388,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(feature = "no-fileline")]
|
# #[cfg(feature = "no-fileline")]
|
||||||
|
# /// Use the `cherr!()` or `mstrerr!()` macro instead of calling this directly
|
||||||
# pub fn new(
|
# pub fn new(
|
||||||
# kind: T,
|
# kind: T,
|
||||||
# error_cause: Option<Box<dyn Error + 'static>>,
|
# error_cause: Option<Box<dyn Error + 'static>>,
|
||||||
|
@ -220,6 +397,7 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Self { kind, error_cause }
|
# Self { kind, error_cause }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /// return the root cause of the error chain, if any exists
|
||||||
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
# pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# while let Some(c) = cause.source() {
|
# while let Some(c) = cause.source() {
|
||||||
|
@ -228,6 +406,54 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# Some(cause)
|
# Some(cause)
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type U, if any exists
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_cause::<io::Error>().is_some());
|
||||||
|
#
|
||||||
|
# assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
# pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -242,6 +468,21 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** find the first error cause of type ChainError<U>, if any exists
|
||||||
|
#
|
||||||
|
# Same as `find_cause`, but hides the `ChainError<U>` implementation internals
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust,ignore
|
||||||
|
# /// Instead of writing
|
||||||
|
# err.find_cause::<ChainError<FooError>>();
|
||||||
|
#
|
||||||
|
# /// leave out the ChainError<T> implementation detail
|
||||||
|
# err.find_chain_cause::<FooError>();
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
# pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
|
||||||
# let mut cause = self as &(dyn Error + 'static);
|
# let mut cause = self as &(dyn Error + 'static);
|
||||||
# loop {
|
# loop {
|
||||||
|
@ -256,19 +497,84 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** return a reference to T of `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# #[derive(Debug)]
|
||||||
|
# enum Func1ErrorKind {
|
||||||
|
# Func2,
|
||||||
|
# IO(String),
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for Func1ErrorKind {…}
|
||||||
|
# # impl ::std::fmt::Display for Func1ErrorKind {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # Func1ErrorKind::Func2 => write!(f, "func1 error calling func2"),
|
||||||
|
# # Func1ErrorKind::IO(filename) => write!(f, "Error reading '{}'", filename),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# fn func1() -> ChainResult<(), Func1ErrorKind> {
|
||||||
|
# func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?;
|
||||||
|
# do_some_io().map_err(|e| cherr!(e, Func1ErrorKind::IO("bar.txt".into())))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn main() {
|
||||||
|
# if let Err(e) = func1() {
|
||||||
|
# match e.kind() {
|
||||||
|
# Func1ErrorKind::Func2 => {},
|
||||||
|
# Func1ErrorKind::IO(filename) => panic!(),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# # else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# pub fn kind<'a>(&'a self) -> &'a T {
|
# pub fn kind<'a>(&'a self) -> &'a T {
|
||||||
# &self.kind
|
# &self.kind
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience trait to hide the `ChainError<T>` implementation internals
|
||||||
|
# **/
|
||||||
# pub trait ChainErrorDown {
|
# pub trait ChainErrorDown {
|
||||||
|
# /** test if of type `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
|
||||||
|
# /** downcast to a reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
# fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
|
||||||
|
# /** downcast to a mutable reference of `ChainError<T>`
|
||||||
|
# **/
|
||||||
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
# fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# use std::any::TypeId;
|
|
||||||
#
|
|
||||||
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
# impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
|
||||||
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
# fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
|
||||||
# TypeId::of::<T>() == TypeId::of::<U>()
|
# TypeId::of::<T>() == TypeId::of::<U>()
|
||||||
|
@ -387,7 +693,11 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# if self.is_chain::<String>() {
|
||||||
|
# Display::fmt(&self.kind, f)?;
|
||||||
|
# } else {
|
||||||
# Debug::fmt(&self.kind, f)?;
|
# Debug::fmt(&self.kind, f)?;
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
# #[cfg(not(feature = "no-debug-cause"))]
|
# #[cfg(not(feature = "no-debug-cause"))]
|
||||||
# {
|
# {
|
||||||
|
@ -400,6 +710,93 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** creates a new `ChainError<T>`
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# Create a new ChainError<FooError>, where `FooError` must implement `Display` and `Debug`.
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# enum FooError {
|
||||||
|
# Bar,
|
||||||
|
# Baz(&'static str),
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
#
|
||||||
|
# // impl ::std::fmt::Display for FooError
|
||||||
|
#
|
||||||
|
# fn do_some_stuff() -> bool {
|
||||||
|
# false
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# if ! do_some_stuff() {
|
||||||
|
# Err(cherr!(FooError::Baz("Error")))?;
|
||||||
|
# }
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# Additionally an error cause can be added.
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use chainerror::*;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# #
|
||||||
|
# # #[derive(Debug)]
|
||||||
|
# # enum FooError {
|
||||||
|
# # Bar,
|
||||||
|
# # Baz(&'static str),
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# # impl ::std::fmt::Display for FooError {
|
||||||
|
# # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
# # match self {
|
||||||
|
# # FooError::Bar => write!(f, "Bar Error"),
|
||||||
|
# # FooError::Baz(s) => write!(f, "Baz Error: '{}'", s),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn do_some_stuff() -> Result<(), Box<Error>> {
|
||||||
|
# Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func() -> ChainResult<(), FooError> {
|
||||||
|
# do_some_stuff().map_err(
|
||||||
|
# |e| cherr!(e, FooError::Baz("Error"))
|
||||||
|
# )?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # pub fn main() {
|
||||||
|
# # match func().unwrap_err().kind() {
|
||||||
|
# # FooError::Baz(s) if s == &"Error" => {},
|
||||||
|
# # _ => panic!(),
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! cherr {
|
# macro_rules! cherr {
|
||||||
# ( $k:expr ) => {
|
# ( $k:expr ) => {
|
||||||
|
@ -410,6 +807,92 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro for |e| cherr!(e, format!(…))
|
||||||
|
#
|
||||||
|
# # Examples
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!("func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # assert_eq!(
|
||||||
|
# # format!("\n{:?}\n", e), r#"
|
||||||
|
# # src/lib.rs:20: func1 error
|
||||||
|
# # Caused by:
|
||||||
|
# # src/lib.rs:15: Error reading 'foo.txt'
|
||||||
|
# # Caused by:
|
||||||
|
# # Kind(NotFound)
|
||||||
|
# # "#
|
||||||
|
# # );
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# `mstrerr!()` can also be used to map a new `ChainError<T>`, where T was defined with
|
||||||
|
# `derive_str_cherr!(T)`
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> Result<(), Box<Error>> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! mstrerr {
|
# macro_rules! mstrerr {
|
||||||
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
# ( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
@ -423,6 +906,49 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
|
# /** convenience macro to create a "new type" T(String) and implement Display + Debug for T
|
||||||
|
#
|
||||||
|
# ~~~rust
|
||||||
|
# # use crate::chainerror::*;
|
||||||
|
# # use std::error::Error;
|
||||||
|
# # use std::io;
|
||||||
|
# # use std::result::Result;
|
||||||
|
# #
|
||||||
|
# # fn do_some_io() -> Result<(), Box<Error>> {
|
||||||
|
# # Err(io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
|
# # Ok(())
|
||||||
|
# # }
|
||||||
|
# #
|
||||||
|
# derive_str_cherr!(Func2Error);
|
||||||
|
#
|
||||||
|
# fn func2() -> ChainResult<(), Func2Error> {
|
||||||
|
# let filename = "foo.txt";
|
||||||
|
# do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# derive_str_cherr!(Func1Error);
|
||||||
|
#
|
||||||
|
# fn func1() -> Result<(), Box<Error>> {
|
||||||
|
# func2().map_err(mstrerr!(Func1Error, "func1 error"))?;
|
||||||
|
# Ok(())
|
||||||
|
# }
|
||||||
|
# #
|
||||||
|
# # fn main() {
|
||||||
|
# # if let Err(e) = func1() {
|
||||||
|
# # if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() {
|
||||||
|
# # assert!(f1err.find_cause::<ChainError<Func2Error>>().is_some());
|
||||||
|
# # assert!(f1err.find_chain_cause::<Func2Error>().is_some());
|
||||||
|
# # } else {
|
||||||
|
# # panic!();
|
||||||
|
# # }
|
||||||
|
# # } else {
|
||||||
|
# # unreachable!();
|
||||||
|
# # }
|
||||||
|
# # }
|
||||||
|
# ~~~
|
||||||
|
#
|
||||||
|
# **/
|
||||||
# #[macro_export]
|
# #[macro_export]
|
||||||
# macro_rules! derive_str_cherr {
|
# macro_rules! derive_str_cherr {
|
||||||
# ($e:ident) => {
|
# ($e:ident) => {
|
||||||
|
@ -440,26 +966,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
# impl ::std::error::Error for $e {}
|
# impl ::std::error::Error for $e {}
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_ref {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_ref::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# #[macro_export]
|
|
||||||
# macro_rules! try_cherr_mut {
|
|
||||||
# ( $e:expr, $t:ident ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# ( $e:expr, $t:path ) => {
|
|
||||||
# $e.downcast_mut::<ChainError<$t>>()
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# }
|
# }
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
|
|
||||||
|
@ -505,12 +1011,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
Loading…
Reference in a new issue