use alloc::boxed::Box;
use core::{error, fmt, ops::Range};
use jiff::{Error as JiffError, civil::DateTime};
macro_rules! err {
($($tt:tt)*) => {{
crate::error::Error::adhoc(format_args!($($tt)*))
}}
}
pub(crate) use err;
#[derive(Clone)]
pub struct Error {
kind: Box<ErrorKind>,
}
impl Error {
#[inline(never)]
#[cold]
pub(crate) fn adhoc(message: impl fmt::Display) -> Error {
Error::from(ErrorKind::Adhoc(AdhocError::from_display(message)))
}
#[inline(never)]
#[cold]
pub(crate) fn range(given: impl Into<i64>, min: impl Into<i64>, max: impl Into<i64>) -> Error {
Error::from(ErrorKind::Range(RangeError::new(given, min, max)))
}
#[inline(never)]
#[cold]
pub(crate) fn datetime_range(what: &'static str, range: Range<DateTime>) -> Error {
Error::from(ErrorKind::DateTimeRange(DateTimeRangeError::new(
what, range,
)))
}
#[inline(never)]
#[cold]
pub(crate) fn jiff(err: JiffError) -> Error {
Error::from(ErrorKind::Jiff(err))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.kind, f)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Error").field("kind", &self.kind).finish()
}
}
impl error::Error for Error {}
impl From<JiffError> for Error {
fn from(err: JiffError) -> Self {
Error::jiff(err)
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Error {
kind: Box::new(kind),
}
}
}
#[derive(Clone, Debug)]
enum ErrorKind {
Adhoc(AdhocError),
Range(RangeError),
DateTimeRange(DateTimeRangeError),
Jiff(JiffError),
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorKind::Adhoc(ref adhoc) => fmt::Display::fmt(adhoc, f),
ErrorKind::Range(ref range) => fmt::Display::fmt(range, f),
ErrorKind::DateTimeRange(ref range) => fmt::Display::fmt(range, f),
ErrorKind::Jiff(ref jiff) => fmt::Display::fmt(jiff, f),
}
}
}
#[derive(Clone)]
struct AdhocError {
message: Box<str>,
}
impl AdhocError {
fn from_display(message: impl fmt::Display) -> AdhocError {
use alloc::string::ToString;
AdhocError {
message: message.to_string().into_boxed_str(),
}
}
}
impl error::Error for AdhocError {}
impl fmt::Display for AdhocError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.message, f)
}
}
impl fmt::Debug for AdhocError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.message, f)
}
}
#[derive(Debug, Clone)]
struct RangeError {
given: i64,
min: i64,
max: i64,
}
impl RangeError {
fn new(given: impl Into<i64>, min: impl Into<i64>, max: impl Into<i64>) -> RangeError {
RangeError {
given: given.into(),
min: min.into(),
max: max.into(),
}
}
}
impl error::Error for RangeError {}
impl fmt::Display for RangeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let RangeError { given, min, max } = *self;
write!(
f,
"parameter with value {given} \
is not in the required range of {min}..={max}",
)
}
}
#[derive(Debug, Clone)]
struct DateTimeRangeError {
what: &'static str,
range: Range<DateTime>,
}
impl DateTimeRangeError {
fn new(what: &'static str, range: Range<DateTime>) -> DateTimeRangeError {
DateTimeRangeError { what, range }
}
}
impl error::Error for DateTimeRangeError {}
impl fmt::Display for DateTimeRangeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{what} end must be greater than start but got {what} range {start}..{end}",
what = self.what,
start = self.range.start,
end = self.range.end
)
}
}