use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
macro_rules! registry {
($($(#[$doc:meta])* $name:ident = $code:literal => $form:literal,)*) => {
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum ErrorCode {
$($(#[$doc])* $name = $code,)*
}
impl ErrorCode {
pub const ALL: &'static [ErrorCode] = &[$(ErrorCode::$name,)*];
#[must_use]
pub const fn form(self) -> &'static str {
match self { $(ErrorCode::$name => $form,)* }
}
#[must_use]
pub const fn number(self) -> u16 {
self as u16
}
}
};
}
registry! {
InvalidPlan = 0x0001 => "invalid argument {}: {}",
ParkFallback = 0x0002 => "completion wait {}: {} is not available on this host ({}), so the declared fallback {} runs",
ExecutorFallback = 0x0003 => "executor {} is not available on this host ({}), so the declared fallback {} runs",
ExecutorRefused = 0x0004 => "executor {} is not available on this host ({}) and the setting is strict: refused",
InvalidExecutor = 0x0005 => "invalid executor {:?}: expected one of {}",
PendedInline = 0x0006 => "{}: a future pended on an inline host",
Stalled = 0x0007 => "executor stalled: {} task(s) pending with no completion source or timer registered",
Backend = 0x0008 => "{} failed with vendor status {}",
}
#[derive(Clone, PartialEq, Eq)]
pub struct Error {
code: ErrorCode,
args: Vec<String>,
}
impl Error {
#[must_use]
pub fn new(code: ErrorCode, args: Vec<String>) -> Self {
Self { code, args }
}
#[must_use]
pub fn code(&self) -> ErrorCode {
self.code
}
#[must_use]
pub fn args(&self) -> &[String] {
&self.args
}
}
#[macro_export]
macro_rules! error {
($code:ident $(, $arg:expr)* $(,)?) => {
$crate::Error::new(
$crate::ErrorCode::$code,
::alloc::vec![$(::alloc::string::ToString::to_string(&$arg)),*],
)
};
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut args = self.args.iter();
let mut rest = self.code.form();
while let Some(i) = rest.find('{') {
f.write_str(&rest[..i])?;
let after = &rest[i..];
let (debug, len) = if after.starts_with("{:?}") {
(true, 4)
} else if after.starts_with("{}") {
(false, 2)
} else {
f.write_str("{")?;
rest = &after[1..];
continue;
};
match args.next() {
Some(a) if debug => write!(f, "{a:?}")?,
Some(a) => f.write_str(a)?,
None => f.write_str("<missing>")?,
}
rest = &after[len..];
}
f.write_str(rest)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{:#06x} {:?}] {self}", self.code.number(), self.code)
}
}
impl core::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;