use std::sync::Arc;
use core::fmt;
use crate::{
data::PackingError,
rawmaster::SlaveAddress,
};
#[derive(Clone, Debug)]
pub enum EthercatError<T=()> {
Io(Arc<std::io::Error>),
Slave(SlaveAddress, T),
Master(&'static str),
Protocol(&'static str),
Timeout(&'static str),
}
pub type EthercatResult<T=(), E=()> = core::result::Result<T, EthercatError<E>>;
impl<T: fmt::Debug> fmt::Display for EthercatError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl<T: fmt::Debug> std::error::Error for EthercatError<T> {}
impl From<EthercatError<()>> for EthercatError<&str> {
fn from(src: EthercatError<()>) -> Self {src.upgrade()}
}
impl<T> From<std::io::Error> for EthercatError<T> {
fn from(src: std::io::Error) -> Self {
EthercatError::Io(Arc::new(src))
}
}
impl<T> From<PackingError> for EthercatError<T> {
fn from(src: PackingError) -> Self {
EthercatError::Protocol(match src {
PackingError::BadSize(_, text) => text,
PackingError::BadAlignment(_, text) => text,
PackingError::InvalidValue(text) => text,
})
}
}
impl<E> EthercatError<E> {
pub fn into<F>(self) -> EthercatError<F>
where F: From<E> {
self.map(|e| F::from(e))
}
pub fn map<F,T>(self, callback: F) -> EthercatError<T>
where F: Fn(E) -> T
{
match self {
EthercatError::Slave(address, value) => EthercatError::Slave(address, callback(value)),
EthercatError::Io(e) => EthercatError::Io(e),
EthercatError::Master(message) => EthercatError::Master(message),
EthercatError::Protocol(message) => EthercatError::Protocol(message),
EthercatError::Timeout(message) => EthercatError::Timeout(message),
}
}
}
impl EthercatError<()> {
pub fn upgrade<F>(self) -> EthercatError<F> {
self.map(|_| unimplemented!("an ethercat error with not slave-specific error type cannot report a slave error"))
}
}