use std::convert::From;
use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::io;
use std::num::TryFromIntError;
use std::sync::Arc;
use bson::error::Error as BsonError;
use bson::error::ErrorKind as BsonErrorKind;
use bson::error::ValueAccessErrorKind;
#[derive(Debug, Clone)]
pub enum MetricParseError {
Io(Arc<io::Error>),
BsonDeserialzation(BsonError),
FieldAccess(KeyAccessError),
UnknownDocumentKind(i32),
MetricCountMismatch,
MetricTimestampNotFound {
name: Arc<str>,
},
IntConversion(TryFromIntError),
}
impl Display for MetricParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let parse_error = "metric parse error:";
match self {
MetricParseError::Io(error) => write!(f, "{parse_error} I/O error: {error}"),
MetricParseError::BsonDeserialzation(error) => {
write!(f, "{parse_error} BSON deserialization error: {error}")
}
MetricParseError::FieldAccess(error) => write!(
f,
"{parse_error} could not read the document field: {error}"
),
MetricParseError::MetricCountMismatch => write!(
f,
"{parse_error} the amount of metrics in the reference document is different than the amount of metric samples"
),
MetricParseError::MetricTimestampNotFound { name } => write!(
f,
"{parse_error} the metric timestamps for the {name} metric could not be found",
),
MetricParseError::IntConversion(error) => {
write!(f, "{parse_error} could not parse integer: {error}")
}
MetricParseError::UnknownDocumentKind(value) => {
write!(f, "{parse_error} unknonw document type: {value}")
}
}
}
}
impl Error for MetricParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
MetricParseError::Io(error) => Some(error),
MetricParseError::BsonDeserialzation(error) => Some(error),
MetricParseError::FieldAccess(error) => Some(error),
MetricParseError::MetricCountMismatch => None,
MetricParseError::MetricTimestampNotFound { .. } => None,
MetricParseError::IntConversion(error) => Some(error),
MetricParseError::UnknownDocumentKind(_) => None,
}
}
}
impl From<io::Error> for MetricParseError {
fn from(error: io::Error) -> Self {
MetricParseError::Io(Arc::new(error))
}
}
impl From<BsonError> for MetricParseError {
fn from(error: BsonError) -> Self {
MetricParseError::BsonDeserialzation(error)
}
}
impl From<TryFromIntError> for MetricParseError {
fn from(error: TryFromIntError) -> Self {
MetricParseError::IntConversion(error)
}
}
impl From<KeyAccessError> for MetricParseError {
fn from(error: KeyAccessError) -> Self {
MetricParseError::FieldAccess(error)
}
}
#[derive(Debug, Clone)]
pub enum KeyAccessError {
KeyNotFound {
key: String,
},
UnexpectedKeyType {
key: String,
},
AccessError {
key: String,
error: String,
},
}
impl Display for KeyAccessError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let key_access_error = "key access error:";
match *self {
KeyAccessError::KeyNotFound { ref key } => {
write!(
f,
"{key_access_error} could not find the field with the {key} key"
)
}
KeyAccessError::UnexpectedKeyType { ref key } => write!(
f,
"{key_access_error} the field with {key} key was found, but not with the expected type"
),
KeyAccessError::AccessError { ref key, ref error } => {
write!(
f,
"{key_access_error} could not access the field value with the {key} key. {error}"
)
}
}
}
}
impl Error for KeyAccessError {}
pub(crate) trait ValueAccessResultExt<T> {
fn map_value_access_err(self, key: &str) -> Result<T, KeyAccessError>;
}
impl<T> ValueAccessResultExt<T> for Result<T, BsonError> {
fn map_value_access_err(self, key: &str) -> Result<T, KeyAccessError> {
self.map_err(|error| match error.kind {
BsonErrorKind::ValueAccess { kind, .. } => match kind {
ValueAccessErrorKind::NotPresent { .. } => KeyAccessError::KeyNotFound {
key: key.to_owned(),
},
ValueAccessErrorKind::UnexpectedType { .. } => KeyAccessError::UnexpectedKeyType {
key: key.to_owned(),
},
e => KeyAccessError::AccessError {
key: key.to_owned(),
error: e.to_string(),
},
},
_ => KeyAccessError::AccessError {
key: key.to_owned(),
error: format!("{error}"),
},
})
}
}