From 0fe87c18816a93f23a4a09525b62e7fec41b1fd2 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 20 Jun 2023 11:50:22 +1000 Subject: [PATCH] Rework the crate error type Currently we are converting error types to strings, this makes the library worse when used with standard error handling crates by downstream users. Instead we can put each error type inside the respective error variant and implement `std::error::Error` so that `source` can be called by error handling libraries for better error output. Please note this removes `PartialEq` and `Eq` from the error type which makes it harder to use. This is an ecosystem-wide problem caused by the `io::Error`, there is currently (to the best of my knowledge) no good solution other than removing the derives. This is an API breaking change. --- src/error.rs | 72 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8283bbb..aa983fb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ use std::convert::TryFrom; -use std::fmt; +use std::{fmt, io, str}; #[derive(Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -71,35 +71,63 @@ impl fmt::Debug for ErrorCode { } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug)] pub enum Error { - Json(String), - Utf8(String), - Io(String), - InvalidOption(String), + Json(serde_json::Error), + Utf8(std::str::Utf8Error), + Io(std::io::Error), Hwi(String, Option), - Python(String), + Python(pyo3::PyErr), } -macro_rules! impl_error { - ( $from:ty, $to:ident ) => { - impl std::convert::From<$from> for Error { - fn from(err: $from) -> Self { - Error::$to(err.to_string()) - } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use Error::*; + + match *self { + Json(_) => f.write_str("serde_json error"), + Utf8(_) => f.write_str("utf8 error"), + Io(_) => f.write_str("I/O error"), + Hwi(ref s, ref code) => write!(f, "HWI error: {}, ({:?})", s, code), + Python(_) => f.write_str("python error"), } - }; + } } -impl_error!(serde_json::Error, Json); -impl_error!(std::str::Utf8Error, Utf8); -impl_error!(std::io::Error, Io); -impl_error!(pyo3::prelude::PyErr, Python); +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) + match *self { + Json(ref e) => Some(e), + Utf8(ref e) => Some(e), + Io(ref e) => Some(e), + Hwi(_, _) => None, + Python(ref e) => Some(e), + } + } +} + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + Error::Json(e) } } -impl std::error::Error for Error {} +impl From for Error { + fn from(e: str::Utf8Error) -> Self { + Error::Utf8(e) + } +} + +impl From for Error { + fn from(e: io::Error) -> Self { + Error::Io(e) + } +} + +impl From for Error { + fn from(e: pyo3::PyErr) -> Self { + Error::Python(e) + } +}