use core::error::Error;
use core::{ffi::c_int, fmt::Display};
pub type ApiResult<T = ()> = core::result::Result<T, ApiError>;
pub type Result<T = ()> = core::result::Result<T, &'static str>;
pub trait ErrorCode {
fn to_result(self) -> ApiResult;
}
impl ErrorCode for c_int {
fn to_result(self) -> ApiResult {
match self {
0 => Ok(()),
n => Err(n.into()),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum ApiError {
UnknownErrorCode(c_int),
Usage,
SemQuery,
Serde(&'static str),
TimedOut,
BufferTooSmall,
NotReady,
SignalLayerClaimed,
Unavailable,
TypeMismatch {
expected: u32,
actual: u32,
},
}
impl Error for ApiError {}
impl Display for ApiError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let msg = match self {
ApiError::UnknownErrorCode(_) => "unknown error code",
ApiError::Usage => "incorrect api usage",
ApiError::SemQuery => "incorrect sem query",
ApiError::Serde(context) => context,
ApiError::TimedOut => "timed out",
ApiError::BufferTooSmall => "scratch buffer too small for payload",
ApiError::NotReady => "not ready, try again",
ApiError::SignalLayerClaimed => "signal layer claimed by another cell",
ApiError::Unavailable => "unavailable, re-resolve the handle",
ApiError::TypeMismatch { .. } => "wire type mismatch between cell and slot",
};
write!(f, "{msg}")
}
}
impl From<c_int> for ApiError {
fn from(value: c_int) -> Self {
match value {
0 => unreachable!("0 is not an error"),
-11 => ApiError::NotReady,
myrmic_common::types::error::ENOMEM => ApiError::BufferTooSmall,
-13 => ApiError::SignalLayerClaimed,
myrmic_common::types::error::ESTALE => ApiError::Unavailable,
-127 => ApiError::Serde("unable to serialise request"),
n => ApiError::UnknownErrorCode(n),
}
}
}
impl From<ApiError> for &'static str {
fn from(value: ApiError) -> Self {
match value {
ApiError::UnknownErrorCode(_) => "unknown error code",
ApiError::Usage => "incorrect api usage",
ApiError::SemQuery => "incorrect sem query",
ApiError::Serde(context) => context,
ApiError::TimedOut => "timed out",
ApiError::BufferTooSmall => "scratch buffer too small for payload",
ApiError::NotReady => "not ready, try again",
ApiError::SignalLayerClaimed => "signal layer claimed by another cell",
ApiError::Unavailable => "unavailable, re-resolve the handle",
ApiError::TypeMismatch { .. } => "wire type mismatch between cell and slot",
}
}
}
#[cfg(test)]
mod tests {
use myrmic_common::types::error::{EINVAL, ESTALE};
use super::ApiError;
#[test]
fn estale_maps_to_unavailable() {
assert!(matches!(ApiError::from(ESTALE), ApiError::Unavailable));
}
#[test]
fn known_codes_keep_their_variants() {
assert!(matches!(ApiError::from(-11), ApiError::NotReady));
assert!(matches!(ApiError::from(-127), ApiError::Serde(_)));
}
#[test]
fn unassigned_codes_stay_unknown() {
assert!(matches!(ApiError::from(-1), ApiError::UnknownErrorCode(-1)));
assert!(matches!(
ApiError::from(EINVAL),
ApiError::UnknownErrorCode(_)
));
}
}