-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Add error::Report type #90174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add error::Report type #90174
Changes from 1 commit
59df6c8
6a59d0e
c6de413
c0f14cb
aa853bd
d2f49ee
32bcb81
840cb00
edd65f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ use crate::backtrace::Backtrace; | |
use crate::borrow::Cow; | ||
use crate::cell; | ||
use crate::char; | ||
use crate::fmt::{self, Debug, Display}; | ||
use crate::fmt::{self, Debug, Display, Write}; | ||
use crate::mem::transmute; | ||
use crate::num; | ||
use crate::str; | ||
|
@@ -807,3 +807,246 @@ impl dyn Error + Send + Sync { | |
}) | ||
} | ||
} | ||
|
||
/// An error reporter that exposes the entire error chain for printing. | ||
/// It also exposes options for formatting the error chain, either entirely on a single line, | ||
/// or in multi-line format with each cause in the error chain on a new line. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// #![feature(error_reporter)] | ||
/// | ||
/// use std::error::{Error, Report}; | ||
/// use std::fmt; | ||
/// | ||
/// #[derive(Debug)] | ||
/// struct SuperError { | ||
/// side: SuperErrorSideKick, | ||
/// } | ||
/// | ||
/// impl fmt::Display for SuperError { | ||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
/// write!(f, "SuperError is here!") | ||
/// } | ||
/// } | ||
/// | ||
/// impl Error for SuperError { | ||
/// fn source(&self) -> Option<&(dyn Error + 'static)> { | ||
/// Some(&self.side) | ||
/// } | ||
/// } | ||
/// | ||
/// #[derive(Debug)] | ||
/// struct SuperErrorSideKick; | ||
/// | ||
/// impl fmt::Display for SuperErrorSideKick { | ||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
/// write!(f, "SuperErrorSideKick is here!") | ||
/// } | ||
/// } | ||
/// | ||
/// impl Error for SuperErrorSideKick {} | ||
/// | ||
/// fn main() { | ||
/// let error = SuperError { side: SuperErrorSideKick }; | ||
/// let report = Report::new(&error).pretty(); | ||
/// | ||
/// println!("{}", report); | ||
/// } | ||
/// ``` | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
pub struct Report<E> { | ||
source: E, | ||
seanchen1991 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
show_backtrace: bool, | ||
pretty: bool, | ||
} | ||
|
||
impl<E> Report<E> | ||
where | ||
E: Error, | ||
{ | ||
/// Create a new `Report` from an input error. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
pub fn new(source: E) -> Report<E> { | ||
Report { source, show_backtrace: false, pretty: false } | ||
} | ||
|
||
/// Enable pretty-printing the report. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
pub fn pretty(mut self) -> Self { | ||
|
||
self.pretty = true; | ||
self | ||
} | ||
|
||
/// Enable showing a backtrace for the report. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
pub fn show_backtrace(mut self) -> Self { | ||
self.show_backtrace = true; | ||
self | ||
} | ||
|
||
/// Format the report as a single line. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self.source)?; | ||
|
||
let sources = self.source.source().into_iter().flat_map(<dyn Error>::chain); | ||
|
||
for cause in sources { | ||
write!(f, ": {}", cause)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Format the report as multiple lines, with each error cause on its own line. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
let error = &self.source; | ||
|
||
write!(f, "{}", error)?; | ||
|
||
if let Some(cause) = error.source() { | ||
write!(f, "\n\nCaused by:")?; | ||
|
||
let multiple = cause.source().is_some(); | ||
let format = if multiple { | ||
Format::Numbered { ind: 0 } | ||
} else { | ||
Format::Uniform { indentation: " " } | ||
}; | ||
|
||
for error in cause.chain() { | ||
writeln!(f)?; | ||
|
||
let mut indented = Indented { inner: f, needs_indent: true, format }; | ||
|
||
write!(indented, "{}", error)?; | ||
} | ||
} | ||
|
||
if self.show_backtrace { | ||
let backtrace = error.backtrace(); | ||
|
||
if let Some(backtrace) = backtrace { | ||
let mut backtrace = backtrace.to_string(); | ||
|
||
write!(f, "\n\n")?; | ||
writeln!(f, "Stack backtrace:")?; | ||
|
||
backtrace.truncate(backtrace.trim_end().len()); | ||
|
||
write!(f, "{}", backtrace)?; | ||
seanchen1991 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
impl<E> From<E> for Report<E> | ||
where | ||
E: Error, | ||
{ | ||
fn from(source: E) -> Self { | ||
Report::new(source) | ||
} | ||
} | ||
|
||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
impl<E> fmt::Display for Report<E> | ||
where | ||
E: Error, | ||
{ | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } | ||
} | ||
} | ||
|
||
// This type intentionally outputs the same format for `Display` and `Debug`for | ||
yaahc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
// situations where you unwrap a `Report` or return it from main. | ||
#[unstable(feature = "error_reporter", issue = "90172")] | ||
impl<E> fmt::Debug for Report<E> | ||
where | ||
E: Error, | ||
{ | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
fmt::Display::fmt(self, f) | ||
} | ||
} | ||
|
||
/// Encapsulates how error sources are indented and formatted. | ||
struct Indented<'a, D: ?Sized> { | ||
inner: &'a mut D, | ||
needs_indent: bool, | ||
format: Format, | ||
} | ||
|
||
/// The possible variants that error sources can be formatted as. | ||
#[derive(Clone, Copy)] | ||
enum Format { | ||
/// Insert uniform indentation before every line. | ||
/// | ||
/// This format takes a static string as input and inserts it after every newline. | ||
Uniform { | ||
/// The string to insert as indentation. | ||
indentation: &'static str, | ||
}, | ||
seanchen1991 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
/// Inserts a number before the first line. | ||
/// | ||
/// This format hard codes the indentation level to match the indentation from | ||
/// `std::backtrace::Backtrace`. | ||
Numbered { | ||
/// The index to insert before the first line of output. | ||
ind: usize, | ||
}, | ||
} | ||
|
||
impl<D> Write for Indented<'_, D> | ||
where | ||
D: Write + ?Sized, | ||
{ | ||
fn write_str(&mut self, s: &str) -> fmt::Result { | ||
for (ind, line) in s.split('\n').enumerate() { | ||
if ind > 0 { | ||
self.inner.write_char('\n')?; | ||
self.needs_indent = true; | ||
} | ||
|
||
if self.needs_indent { | ||
if line.is_empty() { | ||
continue; | ||
} | ||
|
||
self.format.insert_indentation(ind, &mut self.inner)?; | ||
self.needs_indent = false; | ||
} | ||
|
||
self.inner.write_fmt(format_args!("{}", line))?; | ||
seanchen1991 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl Format { | ||
/// Write the specified formatting to the write buffer. | ||
fn insert_indentation(&mut self, line: usize, f: &mut dyn Write) -> fmt::Result { | ||
match self { | ||
Format::Uniform { indentation } => { | ||
write!(f, "{}", indentation) | ||
} | ||
Format::Numbered { ind } => { | ||
if line == 0 { | ||
yaahc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
write!(f, "{: >4}: ", ind)?; | ||
*ind += 1; | ||
yaahc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Ok(()) | ||
} else { | ||
write!(f, " ") | ||
} | ||
} | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.