use crate::address::{Address, Error as AddressError};
use std::{
error::Error as StdError,
fmt::{Display, Formatter, Result as FmtResult},
io::Error as IoError,
path::PathBuf,
result::Result as StdResult,
};
use serde_json::error::Error as SerdeError;
pub type Result<T> = StdResult<T, Error>;
#[derive(Debug)]
pub enum Error {
EmptyTemps { address: Address },
EmptyCurve { address: Address },
Address { source: AddressError },
Index { address: Address },
Average { address: Address },
Load { path: PathBuf, source: IoError },
Parse { source: SerdeError },
Multiple { errors: Vec<Error> },
}
impl Error {
pub(crate) fn new_empty_temps(address: Address) -> Self {
Error::EmptyTemps { address }
}
pub(crate) fn new_empty_curve(address: Address) -> Self {
Error::EmptyCurve { address }
}
pub(crate) fn new_index(address: Address) -> Self {
Error::Index { address }
}
pub(crate) fn new_average(address: Address) -> Self {
Error::Average { address }
}
pub(crate) fn new_load(path: impl Into<PathBuf>, source: IoError) -> Self {
Error::Load {
path: path.into(),
source,
}
}
pub(crate) fn from_vec(errors: Vec<Error>) -> Option<Self> {
match errors.len() {
0 => None,
1 => Some(errors.into_iter().next().unwrap()),
_ => Some(Error::Multiple { errors }),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Error::EmptyTemps { address } => {
write!(f, "Config of channel at address {} has no temps.", address)
}
Error::EmptyCurve { address } => write!(
f,
"Config of channel at address {} has an empty curve.",
address
),
Error::Address { source } => write!(f, "Config has invalid sensor address: {}", source),
Error::Index { address } => write!(
f,
"Config of channel at address {} has no index or index is not above zero.",
address
),
Error::Average { address } => write!(
f,
"Config of channel at address {} has an average below one or above 10.",
address
),
Error::Load { path, source } => {
write!(f, "Error loading config at {}: {}", path.display(), source)
}
Error::Parse { source } => write!(f, "Error parsing config: {}", source),
Error::Multiple { errors } => {
write!(f, "Multiple errors occurred:")?;
for error in errors {
write!(f, "\n{}", error)?;
}
Ok(())
}
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Error::EmptyTemps { .. } => None,
Error::EmptyCurve { .. } => None,
Error::Address { source } => Some(source),
Error::Index { .. } => None,
Error::Average { .. } => None,
Error::Load { source, .. } => Some(source),
Error::Parse { source } => Some(source),
Error::Multiple { errors } => errors.first().and_then(StdError::source),
}
}
}
impl From<SerdeError> for Error {
fn from(source: SerdeError) -> Self {
Error::Parse { source }
}
}
impl From<AddressError> for Error {
fn from(source: AddressError) -> Self {
Error::Address { source }
}
}