1use std::fmt; 2 3/// What can go wrong with the database. What the adapters report to their ports is only a sentence for the 4/// log (the ports' own errors say whether to retry); this keeps the cause. 5#[derive(Debug)] 6pub enum DbError { 7 /// SQLite refused or failed. 8 Sqlite(rusqlite::Error), 9 /// The database was written by a newer build than this one. 10 Newer { found: u32, known: u32 }, 11 /// Something another connection holds stopped a checkpoint. 12 Busy, 13 /// What is stored does not read back as what it should be. 14 Damaged(String), 15} 16 17impl fmt::Display for DbError { 18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 19 match self { 20 DbError::Sqlite(e) => write!(f, "database error: {e}"), 21 DbError::Newer { found, known } => write!(f, "the database is at version {found}, newer than this build's {known}"), 22 DbError::Busy => write!(f, "the database is busy"), 23 DbError::Damaged(what) => write!(f, "the database is damaged: {what}"), 24 } 25 } 26} 27 28impl DbError { 29 /// Whether what is stored is not a database at all, or is broken beyond reading: the file is damaged and 30 /// not merely busy, full or from a newer build. 31 pub fn is_unreadable(&self) -> bool { 32 match self { 33 DbError::Sqlite(rusqlite::Error::SqliteFailure(e, _)) => matches!(e.code, rusqlite::ErrorCode::NotADatabase | rusqlite::ErrorCode::DatabaseCorrupt), 34 DbError::Damaged(_) => true, 35 _ => false, 36 } 37 } 38 39 /// Whether the database was written by a newer build. 40 pub fn is_newer(&self) -> bool { 41 matches!(self, DbError::Newer { .. }) 42 } 43} 44 45impl std::error::Error for DbError {} 46 47impl From<rusqlite::Error> for DbError { 48 fn from(e: rusqlite::Error) -> Self { 49 DbError::Sqlite(e) 50 } 51}