use {
anstream::{print, println},
owo_colors::*,
problemo::*,
std::{any::*, error::*, fmt},
};
fn read_file(path: &str) -> Result<String, Problem> {
std::fs::read_to_string(path).via(ReadError::new(path.into()).pretty())
}
fn main() {
if let Err(problem) = read_file("non-existing.txt") {
for cause in &problem {
print!("• ");
match cause.error.downcast_ref::<PrettyErrorRef>() {
Some(pretty_error) => {
pretty_error.pretty_print();
if let Some(_read_error) = pretty_error.downcast_ref::<ReadError>() {
println!(" (This is a ReadError)");
}
}
None => println!("{}", cause.error),
}
}
}
}
#[derive(Debug)]
pub struct ReadError {
pub path: String,
}
impl ReadError {
pub fn new(path: String) -> Self {
Self { path }
}
}
impl fmt::Display for ReadError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "could not read from: {}'", self.path)
}
}
impl Error for ReadError {}
impl Pretty for ReadError {
fn pretty_print(&self) {
println!("could not read from: {}", self.path.red().underline());
}
}
pub trait Pretty {
fn pretty_print(&self);
}
pub trait AsAnyRef {
fn as_any_ref(&self) -> Option<&dyn Any>;
}
impl<ErrorT> AsAnyRef for ErrorT
where
ErrorT: 'static + Error,
{
fn as_any_ref(&self) -> Option<&dyn Any> {
Some(self)
}
}
pub trait PrettyError: AsAnyRef + Error + Pretty {}
impl<ErrorT> PrettyError for ErrorT where ErrorT: 'static + Error + Pretty {}
pub struct PrettyErrorRef(Box<dyn PrettyError + Send + Sync>);
impl PrettyErrorRef {
pub fn new<ErrorT>(error: ErrorT) -> Self
where
ErrorT: 'static + Error + Pretty + Send + Sync,
{
Self(Box::new(error))
}
pub fn downcast_ref<AnyT>(&self) -> Option<&AnyT>
where
AnyT: 'static,
{
self.as_ref()
.as_any_ref()
.and_then(|any| any.downcast_ref())
}
}
impl AsRef<dyn 'static + PrettyError + Send + Sync> for PrettyErrorRef {
fn as_ref(&self) -> &(dyn 'static + PrettyError + Send + Sync) {
self.0.as_ref()
}
}
impl fmt::Debug for PrettyErrorRef {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt("Box<dyn PrettyError + Send + Sync>", formatter)
}
}
impl fmt::Display for PrettyErrorRef {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_ref(), formatter)
}
}
impl Error for PrettyErrorRef {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.as_ref().source()
}
}
impl Pretty for PrettyErrorRef {
fn pretty_print(&self) {
self.as_ref().pretty_print();
}
}
pub trait IntoPrettyErrorRef {
fn pretty(self) -> PrettyErrorRef;
}
impl<ErrorT> IntoPrettyErrorRef for ErrorT
where
ErrorT: 'static + Error + Pretty + Send + Sync,
{
fn pretty(self) -> PrettyErrorRef {
PrettyErrorRef::new(self)
}
}