use std::fmt;
use std::time::SystemTimeError;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct Error(ErrorKind);
crate::thread_aware_move!(Error);
#[derive(Debug)]
enum ErrorKind {
#[cfg(any(feature = "fmt", test))]
Jiff(jiff::Error),
#[cfg(any(feature = "fmt", test))]
OutOfRange(std::borrow::Cow<'static, str>),
Other(Box<dyn std::error::Error + Send + Sync + 'static>),
SystemTimeError(SystemTimeError),
}
impl Error {
const fn from_kind(kind: ErrorKind) -> Self {
Self(kind)
}
#[cfg(any(feature = "fmt", test))]
pub(super) fn out_of_range(message: impl Into<std::borrow::Cow<'static, str>>) -> Self {
Self::from_kind(ErrorKind::OutOfRange(message.into()))
}
#[cfg(any(feature = "fmt", test))]
pub(super) const fn jiff(error: jiff::Error) -> Self {
Self::from_kind(ErrorKind::Jiff(error))
}
pub(super) fn other(error: impl std::error::Error + Send + Sync + 'static) -> Self {
Self::from_kind(ErrorKind::Other(Box::new(error)))
}
#[cfg(test)]
const fn kind(&self) -> &ErrorKind {
&self.0
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
#[cfg(any(feature = "fmt", test))]
ErrorKind::Jiff(err) => err.fmt(f),
#[cfg(any(feature = "fmt", test))]
ErrorKind::OutOfRange(msg) => write!(f, "{msg}"),
ErrorKind::Other(err) => err.fmt(f),
ErrorKind::SystemTimeError(err) => err.fmt(f),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.0 {
#[cfg(any(feature = "fmt", test))]
ErrorKind::Jiff(err) => Some(err),
#[cfg(any(feature = "fmt", test))]
ErrorKind::OutOfRange(_) => None,
ErrorKind::Other(err) => Some(err.as_ref()),
ErrorKind::SystemTimeError(err) => Some(err),
}
}
}
impl From<SystemTimeError> for Error {
fn from(err: SystemTimeError) -> Self {
Self(ErrorKind::SystemTimeError(err))
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use std::error::Error as StdError;
use std::time::{Duration, UNIX_EPOCH};
use jiff::SignedDuration;
use thread_aware::ThreadAware;
use thread_aware::affinity::pinned_affinities;
use super::*;
#[test]
fn assert_types() {
static_assertions::assert_impl_all!(Error: Send, Sync);
}
#[test]
fn jiff_error() {
let error = jiff::Timestamp::from_duration(SignedDuration::MAX).unwrap_err();
let error = Error::jiff(error);
assert!(matches!(error.kind(), ErrorKind::Jiff(_)));
assert_eq!(
error.to_string(),
"parameter 'Unix timestamp seconds' is not in the required range of -377705023201..=253402207200"
);
assert!(error.source().is_some());
}
#[test]
fn out_of_range_error() {
let error = Error::out_of_range("test");
assert!(matches!(error.kind(), ErrorKind::OutOfRange(_)));
assert_eq!(error.to_string(), "test");
assert!(error.source().is_none());
}
#[test]
fn from_other_ok() {
let error = Error::other(std::io::Error::other("dummy"));
assert!(matches!(error.kind(), ErrorKind::Other(_)));
assert_eq!(error.to_string(), "dummy");
assert_eq!(error.source().unwrap().to_string(), "dummy");
}
#[test]
fn from_system_time_error() {
let later = UNIX_EPOCH + Duration::from_secs(1);
let system_time_error = UNIX_EPOCH.duration_since(later).unwrap_err();
let expected_message = system_time_error.to_string();
let error = Error::from(system_time_error);
assert!(matches!(error.kind(), ErrorKind::SystemTimeError(_)));
assert_eq!(error.to_string(), expected_message);
assert!(error.source().is_some());
}
#[test]
fn thread_aware_ok() {
let error = Error::other(std::io::Error::other("dummy"));
let affinities = pinned_affinities(&[2]);
let mut error = error;
error.relocate(Some(affinities[0]), affinities[0]);
assert!(matches!(error.kind(), ErrorKind::Other(_)));
}
}