use std::fmt;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ErrorCode {
NotAGitRepository,
NotInitialized,
InvalidConfig,
InvalidRecord,
ImmutableRecordChanged,
SemanticConflict,
IndexCorrupt,
IndexBusy,
PathOutsideRepository,
McpProtocolError,
AuditWriteFailed,
TeamMemoryBehind,
TeamMemoryUnknown,
ChangeRecordRequired,
DuplicateKeyConfirmationRequired,
KeyAliasConflict,
KeyAliasCycle,
BackfillDraftInvalid,
ArchivePlanMismatch,
ArchiveRefMissing,
P1NotImplemented,
Internal,
}
impl ErrorCode {
pub const ALL: &'static [ErrorCode] = &[
ErrorCode::NotAGitRepository,
ErrorCode::NotInitialized,
ErrorCode::InvalidConfig,
ErrorCode::InvalidRecord,
ErrorCode::ImmutableRecordChanged,
ErrorCode::SemanticConflict,
ErrorCode::IndexCorrupt,
ErrorCode::IndexBusy,
ErrorCode::PathOutsideRepository,
ErrorCode::McpProtocolError,
ErrorCode::AuditWriteFailed,
ErrorCode::TeamMemoryBehind,
ErrorCode::TeamMemoryUnknown,
ErrorCode::ChangeRecordRequired,
ErrorCode::DuplicateKeyConfirmationRequired,
ErrorCode::KeyAliasConflict,
ErrorCode::KeyAliasCycle,
ErrorCode::BackfillDraftInvalid,
ErrorCode::ArchivePlanMismatch,
ErrorCode::ArchiveRefMissing,
ErrorCode::P1NotImplemented,
ErrorCode::Internal,
];
pub fn as_str(self) -> &'static str {
match self {
ErrorCode::NotAGitRepository => "NOT_A_GIT_REPOSITORY",
ErrorCode::NotInitialized => "NOT_INITIALIZED",
ErrorCode::InvalidConfig => "INVALID_CONFIG",
ErrorCode::InvalidRecord => "INVALID_RECORD",
ErrorCode::ImmutableRecordChanged => "IMMUTABLE_RECORD_CHANGED",
ErrorCode::SemanticConflict => "SEMANTIC_CONFLICT",
ErrorCode::IndexCorrupt => "INDEX_CORRUPT",
ErrorCode::IndexBusy => "INDEX_BUSY",
ErrorCode::PathOutsideRepository => "PATH_OUTSIDE_REPOSITORY",
ErrorCode::McpProtocolError => "MCP_PROTOCOL_ERROR",
ErrorCode::AuditWriteFailed => "AUDIT_WRITE_FAILED",
ErrorCode::TeamMemoryBehind => "TEAM_MEMORY_BEHIND",
ErrorCode::TeamMemoryUnknown => "TEAM_MEMORY_UNKNOWN",
ErrorCode::ChangeRecordRequired => "CHANGE_RECORD_REQUIRED",
ErrorCode::DuplicateKeyConfirmationRequired => "DUPLICATE_KEY_CONFIRMATION_REQUIRED",
ErrorCode::KeyAliasConflict => "KEY_ALIAS_CONFLICT",
ErrorCode::KeyAliasCycle => "KEY_ALIAS_CYCLE",
ErrorCode::BackfillDraftInvalid => "BACKFILL_DRAFT_INVALID",
ErrorCode::ArchivePlanMismatch => "ARCHIVE_PLAN_MISMATCH",
ErrorCode::ArchiveRefMissing => "ARCHIVE_REF_MISSING",
ErrorCode::P1NotImplemented => "P1_NOT_IMPLEMENTED",
ErrorCode::Internal => "INTERNAL",
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, thiserror::Error)]
#[error("{code}: {message}")]
pub struct MemlayError {
pub code: ErrorCode,
pub message: String,
}
impl MemlayError {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
}
pub fn err(code: ErrorCode, message: impl Into<String>) -> anyhow::Error {
anyhow::Error::new(MemlayError::new(code, message))
}
pub fn code_of(e: &anyhow::Error) -> ErrorCode {
e.downcast_ref::<MemlayError>()
.map(|m| m.code)
.unwrap_or(ErrorCode::Internal)
}