use std::process::ExitCode as ProcExitCode;
use kiromi_ai_memory::Error as CoreError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ExitCode {
Success,
Generic,
Config,
NotFound,
Tombstoned,
Backend,
Embedder,
Mismatch,
}
impl ExitCode {
#[must_use]
pub(crate) fn into_proc(self) -> ProcExitCode {
ProcExitCode::from(self.as_u8())
}
#[must_use]
pub(crate) fn as_u8(self) -> u8 {
match self {
ExitCode::Success => 0,
ExitCode::Generic => 1,
ExitCode::Config => 2,
ExitCode::NotFound => 3,
ExitCode::Tombstoned => 4,
ExitCode::Backend => 5,
ExitCode::Embedder => 6,
ExitCode::Mismatch => 7,
}
}
}
#[derive(Debug)]
pub(crate) struct CliError {
pub(crate) kind: ExitCode,
pub(crate) source: anyhow::Error,
}
impl std::fmt::Display for CliError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.source)
}
}
impl std::error::Error for CliError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(self.source.as_ref())
}
}
impl From<CoreError> for CliError {
fn from(e: CoreError) -> Self {
let kind = exit_code_for(&e);
CliError {
kind,
source: anyhow::Error::new(e),
}
}
}
pub(crate) fn exit_code_for(e: &CoreError) -> ExitCode {
match e {
CoreError::Storage { .. }
| CoreError::Metadata { .. }
| CoreError::IndexCorrupt(_)
| CoreError::Recovery(_)
| CoreError::Io(_) => ExitCode::Backend,
CoreError::Embedder { .. } => ExitCode::Embedder,
CoreError::EmbedderMismatch { .. } | CoreError::PartitionSchemeMismatch { .. } => {
ExitCode::Mismatch
}
CoreError::PartitionInvalid(_)
| CoreError::PartitionSchemeInvalid(_)
| CoreError::TenantInvalid(_)
| CoreError::Config(_)
| CoreError::LinkInvalid(_) => ExitCode::Config,
CoreError::MemoryNotFound(_) => ExitCode::NotFound,
CoreError::Tombstoned(_) => ExitCode::Tombstoned,
_ => ExitCode::Generic,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_variants_map_correctly() {
assert_eq!(
exit_code_for(&CoreError::MemoryNotFound("x".into())),
ExitCode::NotFound
);
assert_eq!(
exit_code_for(&CoreError::Tombstoned("x".into())),
ExitCode::Tombstoned
);
assert_eq!(
exit_code_for(&CoreError::Config("bad".into())),
ExitCode::Config
);
}
}