From b1299c87754366034b3937f01c3ebba889646182 Mon Sep 17 00:00:00 2001 From: Rohan Vanheusden Date: Thu, 8 Jul 2021 12:21:06 -0700 Subject: [PATCH] Impl the standard Error type via thiserror --- lib/Cargo.toml | 11 +++--- lib/src/config.rs | 2 +- lib/src/convert.rs | 38 +++++++++---------- lib/src/errors.rs | 81 ++++++++++++++++++++++++++++------------ lib/src/messages.rs | 2 +- lib/src/types/binary.rs | 8 ++-- lib/src/types/boolean.rs | 5 ++- lib/src/types/date.rs | 2 +- lib/src/types/integer.rs | 7 +++- lib/src/types/list.rs | 8 ++-- lib/src/types/map.rs | 8 ++-- lib/src/types/string.rs | 10 ++--- lib/src/version.rs | 5 +-- 13 files changed, 113 insertions(+), 74 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 8028f8b1..e1fc7e5d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -14,14 +14,15 @@ categories = ["database", "network-programming", "asynchronous"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -neo4rs-macros = { version = "0.2.1", path = "../macros" } -futures = { version = "0.3.8" } -tokio = { version = "1.0.1", features = ["full"] } -bytes = "1.0.0" async-trait = "0.1.42" -deadpool = "0.7.0" +bytes = "1.0.0" chrono = "0.4.19" +deadpool = "0.7.0" +futures = { version = "0.3.8" } log = "0.4" +neo4rs-macros = { version = "0.2.1", path = "../macros" } +thiserror = "1.0.26" +tokio = { version = "1.0.1", features = ["full"] } [dev-dependencies] uuid = { version = "0.8", features = ["v4"] } diff --git a/lib/src/config.rs b/lib/src/config.rs index cfacc51f..14a46570 100644 --- a/lib/src/config.rs +++ b/lib/src/config.rs @@ -71,7 +71,7 @@ impl ConfigBuilder { || self.max_connections.is_none() || self.db.is_none() { - Err(Error::InvalidConfig) + Err(Error::InvalidConfig("a config field was None".into())) } else { //The config attributes are validated before unwrapping Ok(Config { diff --git a/lib/src/convert.rs b/lib/src/convert.rs index 798ac9a9..3b6f072b 100644 --- a/lib/src/convert.rs +++ b/lib/src/convert.rs @@ -9,7 +9,7 @@ impl TryFrom for f64 { fn try_from(input: BoltType) -> Result { match input { BoltType::Float(t) => Ok(t.value), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -20,7 +20,7 @@ impl TryFrom for i64 { fn try_from(input: BoltType) -> Result { match input { BoltType::Integer(t) => Ok(t.value), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -31,7 +31,7 @@ impl TryFrom for bool { fn try_from(input: BoltType) -> Result { match input { BoltType::Boolean(t) => Ok(t.value), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -42,7 +42,7 @@ impl TryFrom for Point2D { fn try_from(input: BoltType) -> Result { match input { BoltType::Point2D(p) => Ok(Point2D::new(p)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -53,7 +53,7 @@ impl TryFrom for std::time::Duration { fn try_from(input: BoltType) -> Result { match input { BoltType::Duration(d) => Ok(d.into()), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -64,7 +64,7 @@ impl TryFrom for chrono::NaiveDate { fn try_from(input: BoltType) -> Result { match input { BoltType::Date(d) => d.try_into(), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -75,7 +75,7 @@ impl TryFrom for chrono::DateTime { fn try_from(input: BoltType) -> Result> { match input { BoltType::DateTime(d) => d.try_into(), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -86,7 +86,7 @@ impl TryFrom for chrono::NaiveDateTime { fn try_from(input: BoltType) -> Result { match input { BoltType::LocalDateTime(d) => d.try_into(), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -105,7 +105,7 @@ impl TryFrom for (chrono::NaiveTime, Option) { } } BoltType::LocalTime(d) => Ok((d.into(), None)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -116,7 +116,7 @@ impl TryFrom for (chrono::NaiveDateTime, String) { fn try_from(input: BoltType) -> Result<(chrono::NaiveDateTime, String)> { match input { BoltType::DateTimeZoneId(date_time_zone_id) => date_time_zone_id.try_into(), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -127,7 +127,7 @@ impl TryFrom for Vec { fn try_from(input: BoltType) -> Result> { match input { BoltType::Bytes(b) => Ok(b.value.to_vec()), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -138,7 +138,7 @@ impl TryFrom for Point3D { fn try_from(input: BoltType) -> Result { match input { BoltType::Point3D(p) => Ok(Point3D::new(p)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -149,7 +149,7 @@ impl TryFrom for Node { fn try_from(input: BoltType) -> Result { match input { BoltType::Node(n) => Ok(Node::new(n)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -160,7 +160,7 @@ impl TryFrom for Path { fn try_from(input: BoltType) -> Result { match input { BoltType::Path(n) => Ok(Path::new(n)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -171,7 +171,7 @@ impl TryFrom for Relation { fn try_from(input: BoltType) -> Result { match input { BoltType::Relation(r) => Ok(Relation::new(r)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -182,7 +182,7 @@ impl TryFrom for UnboundedRelation { fn try_from(input: BoltType) -> Result { match input { BoltType::UnboundedRelation(r) => Ok(UnboundedRelation::new(r)), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -192,7 +192,7 @@ impl TryFrom for BoltList { fn try_from(input: BoltType) -> Result { match input { BoltType::List(l) => Ok(l), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -202,7 +202,7 @@ impl TryFrom for BoltString { fn try_from(input: BoltType) -> Result { match input { BoltType::String(s) => Ok(s), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } @@ -212,7 +212,7 @@ impl TryFrom for String { fn try_from(input: BoltType) -> Result { match input { BoltType::String(t) => Ok(t.value), - _ => Err(Error::ConverstionError), + _ => Err(Error::ConvertError(input)), } } } diff --git a/lib/src/errors.rs b/lib/src/errors.rs index d56b8a42..6f31a27a 100644 --- a/lib/src/errors.rs +++ b/lib/src/errors.rs @@ -1,44 +1,77 @@ +use std::{io, string::FromUtf8Error}; + +use deadpool::managed::PoolError; + +use crate::types::{BoltDate, BoltType}; + pub type Result = std::result::Result; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { - IOError { detail: String }, - ConnectionError, + #[error("an IO error occurred")] + IoError(#[from] io::Error), + + #[error("connection pool error: {0:?}")] + ConnectionError(Box>), + + #[error("attempted to serialize excessively long string")] StringTooLong, + + #[error("attempted to serialize excessively large map")] MapTooBig, + + #[error("attempted to serialize excessively large byte array")] BytesTooBig, + + #[error("attempted to serialize excessively long list")] ListTooLong, - InvalidConfig, - UnsupportedVersion(String), - UnexpectedMessage(String), + + #[error("invalid config: {0}")] + InvalidConfig(String), + + #[error("version {0} is not supported")] + UnsupportedVersion(u32), + + #[error("an unexpected response was received for `{request}`: {response}")] + UnexpectedMessage { + request: String, + response: String + }, + + #[error("attempted to parse unknown type: `{0}`")] UnknownType(String), + + #[error("received unknown message: {0}")] UnknownMessage(String), - ConverstionError, + + #[error("attempted to convert {0:?} into differing native type")] + ConvertError(BoltType), + + #[error("failed to convert `{0:?}` into native type")] + DateConvertError(BoltDate), + + #[error("authentication error: {0}")] AuthenticationError(String), - InvalidTypeMarker(String), - DeserializationError(String), -} -impl std::convert::From for Error { - fn from(e: std::io::Error) -> Self { - Error::IOError { - detail: e.to_string(), - } - } + #[error("invalid {type_name} marker: {marker}")] + InvalidTypeMarker { + type_name: &'static str, + marker: u8, + }, + + #[error("deserialization error")] + DeserializationError(#[from] FromUtf8Error), } -impl std::convert::From> for Error { - fn from(e: deadpool::managed::PoolError) -> Self { +impl From> for Error { + fn from(e: PoolError) -> Self { match e { - deadpool::managed::PoolError::Backend(e) => e, - _ => Error::ConnectionError, + PoolError::Backend(e) => e, + _ => Error::ConnectionError(Box::new(e)), } } } pub fn unexpected(response: T, request: &str) -> Error { - Error::UnexpectedMessage(format!( - "unexpected response for {}: {:?}", - request, response - )) + Error::UnexpectedMessage { request: request.into(), response: format!("{:?}", response) } } diff --git a/lib/src/messages.rs b/lib/src/messages.rs index 44919fa0..86a044c6 100644 --- a/lib/src/messages.rs +++ b/lib/src/messages.rs @@ -114,7 +114,7 @@ impl BoltResponse { input if Record::can_parse(version, input.clone()) => { Ok(BoltResponse::RecordMessage(Record::parse(version, input)?)) } - msg => Err(Error::UnknownMessage(format!("unknown message {:?}", msg))), + msg => Err(Error::UnknownMessage(format!("{:?}", msg))), } } } diff --git a/lib/src/types/binary.rs b/lib/src/types/binary.rs index 5a59854b..b87b5a59 100644 --- a/lib/src/types/binary.rs +++ b/lib/src/types/binary.rs @@ -61,10 +61,10 @@ impl BoltBytes { MEDIUM => input.borrow_mut().get_u16() as usize, LARGE => input.borrow_mut().get_u32() as usize, _ => { - return Err(Error::InvalidTypeMarker(format!( - "invalid bytes marker {}", - marker - ))) + return Err(Error::InvalidTypeMarker { + type_name: "bytes", + marker, + }) } }; diff --git a/lib/src/types/boolean.rs b/lib/src/types/boolean.rs index aac06d40..881b121f 100644 --- a/lib/src/types/boolean.rs +++ b/lib/src/types/boolean.rs @@ -37,7 +37,10 @@ impl BoltBoolean { match value { TRUE => Ok(BoltBoolean::new(true)), FALSE => Ok(BoltBoolean::new(false)), - _ => Err(Error::InvalidTypeMarker("invalid boolean marker".into())), + marker => Err(Error::InvalidTypeMarker { + type_name: "boolean", + marker, + }), } } } diff --git a/lib/src/types/date.rs b/lib/src/types/date.rs index a2312358..724dff2f 100644 --- a/lib/src/types/date.rs +++ b/lib/src/types/date.rs @@ -26,7 +26,7 @@ impl TryInto for BoltDate { let days = Duration::days(self.days.value); epoch .checked_add_signed(days) - .ok_or(Error::ConverstionError) + .ok_or(Error::DateConvertError(self.clone())) } } diff --git a/lib/src/types/integer.rs b/lib/src/types/integer.rs index 6418acc5..3aeb58ef 100644 --- a/lib/src/types/integer.rs +++ b/lib/src/types/integer.rs @@ -56,7 +56,12 @@ impl BoltInteger { INT_16 => input.get_i16() as i64, INT_32 => input.get_i32() as i64, INT_64 => input.get_i64() as i64, - _ => return Err(Error::InvalidTypeMarker("invalid integer marker".into())), + marker => { + return Err(Error::InvalidTypeMarker { + type_name: "integer", + marker, + }) + } }; Ok(BoltInteger::new(value)) diff --git a/lib/src/types/list.rs b/lib/src/types/list.rs index 02594931..4130667b 100644 --- a/lib/src/types/list.rs +++ b/lib/src/types/list.rs @@ -123,10 +123,10 @@ impl BoltList { MEDIUM => input.borrow_mut().get_u16() as usize, LARGE => input.borrow_mut().get_u32() as usize, _ => { - return Err(Error::InvalidTypeMarker(format!( - "invalid list marker {}", - marker - ))) + return Err(Error::InvalidTypeMarker { + type_name: "list", + marker, + }) } }; diff --git a/lib/src/types/map.rs b/lib/src/types/map.rs index aebc1c91..8934007b 100644 --- a/lib/src/types/map.rs +++ b/lib/src/types/map.rs @@ -122,10 +122,10 @@ impl BoltMap { MEDIUM => input.borrow_mut().get_u16() as usize, LARGE => input.borrow_mut().get_u32() as usize, _ => { - return Err(Error::InvalidTypeMarker(format!( - "invalid map marker {}", - marker - ))) + return Err(Error::InvalidTypeMarker { + type_name: "map", + marker, + }) } }; diff --git a/lib/src/types/string.rs b/lib/src/types/string.rs index 958d16a9..b70a79e1 100644 --- a/lib/src/types/string.rs +++ b/lib/src/types/string.rs @@ -91,15 +91,15 @@ impl BoltString { MEDIUM => input.get_u16() as usize, LARGE => input.get_u32() as usize, _ => { - return Err(Error::InvalidTypeMarker(format!( - "invalid string marker {}", - marker - ))) + return Err(Error::InvalidTypeMarker { + type_name: "string", + marker, + }) } }; let byte_array = input.split_to(length).to_vec(); let string_value = std::string::String::from_utf8(byte_array) - .map_err(|e| Error::DeserializationError(e.to_string()))?; + .map_err(Error::DeserializationError)?; Ok(string_value.into()) } } diff --git a/lib/src/version.rs b/lib/src/version.rs index e0ba1dec..76b9bbb7 100644 --- a/lib/src/version.rs +++ b/lib/src/version.rs @@ -23,10 +23,7 @@ impl Version { match u32::from_be_bytes(version_bytes) { 260 => Ok(Version::V4_1), 4 => Ok(Version::V4), - v => Err(Error::UnsupportedVersion(format!( - "version {} is not supported", - v - ))), + v => Err(Error::UnsupportedVersion(v)), } } }