mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 15:02:21 -04:00

* Add crate snafu * Replace all inline structs in AnkiError * Derive Snafu on AnkiError * Use snafu for card type errors * Use snafu whatever error for InvalidInput * Use snafu for NotFoundError and improve message * Use snafu for FileIoError to attach context Remove IoError. Add some context-attaching helpers to replace code returning bare io::Errors. * Add more context-attaching io helpers * Add message, context and backtrace to new snafus * Utilize error context and backtrace on frontend * Rename LocalizedError -> BackendError. * Remove DocumentedError. * Have all backend exceptions inherit BackendError. * Rename localized(_description) -> message * Remove accidentally committed experimental trait * invalid_input_context -> ok_or_invalid * ensure_valid_input! -> require! * Always return `Err` from `invalid_input!` Instead of a Result to unwrap, the macro accepts a source error now. * new_tempfile_in_parent -> new_tempfile_in_parent_of * ok_or_not_found -> or_not_found * ok_or_invalid -> or_invalid * Add crate convert_case * Use unqualified lowercase type name * Remove uses of snafu::ensure * Allow public construction of InvalidInputErrors (dae) Needed to port the AnkiDroid changes. * Make into_protobuf() public (dae) Also required for AnkiDroid. Not sure why it worked previously - possible bug in older Rust version?
96 lines
2.5 KiB
Rust
96 lines
2.5 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use std::str::Utf8Error;
|
|
|
|
use anki_i18n::I18n;
|
|
use rusqlite::{types::FromSqlError, Error};
|
|
use snafu::Snafu;
|
|
|
|
use super::AnkiError;
|
|
|
|
#[derive(Debug, PartialEq, Eq, Snafu)]
|
|
pub struct DbError {
|
|
pub info: String,
|
|
pub kind: DbErrorKind,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum DbErrorKind {
|
|
FileTooNew,
|
|
FileTooOld,
|
|
MissingEntity,
|
|
Corrupt,
|
|
Locked,
|
|
Utf8,
|
|
Other,
|
|
}
|
|
|
|
impl AnkiError {
|
|
pub(crate) fn db_error(info: impl Into<String>, kind: DbErrorKind) -> Self {
|
|
AnkiError::DbError {
|
|
source: DbError {
|
|
info: info.into(),
|
|
kind,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Error> for AnkiError {
|
|
fn from(err: Error) -> Self {
|
|
if let Error::SqliteFailure(error, Some(reason)) = &err {
|
|
if error.code == rusqlite::ErrorCode::DatabaseBusy {
|
|
return AnkiError::DbError {
|
|
source: DbError {
|
|
info: "".to_string(),
|
|
kind: DbErrorKind::Locked,
|
|
},
|
|
};
|
|
}
|
|
if reason.contains("regex parse error") {
|
|
return AnkiError::InvalidRegex {
|
|
info: reason.to_owned(),
|
|
};
|
|
}
|
|
}
|
|
AnkiError::DbError {
|
|
source: DbError {
|
|
info: format!("{:?}", err),
|
|
kind: DbErrorKind::Other,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<FromSqlError> for AnkiError {
|
|
fn from(err: FromSqlError) -> Self {
|
|
if let FromSqlError::Other(ref err) = err {
|
|
if let Some(_err) = err.downcast_ref::<Utf8Error>() {
|
|
return AnkiError::DbError {
|
|
source: DbError {
|
|
info: "".to_string(),
|
|
kind: DbErrorKind::Utf8,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
AnkiError::DbError {
|
|
source: DbError {
|
|
info: format!("{:?}", err),
|
|
kind: DbErrorKind::Other,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DbError {
|
|
pub fn message(&self, _tr: &I18n) -> String {
|
|
match self.kind {
|
|
DbErrorKind::Corrupt => self.info.clone(),
|
|
// fixme: i18n
|
|
DbErrorKind::Locked => "Anki already open, or media currently syncing.".into(),
|
|
_ => format!("{:?}", self),
|
|
}
|
|
}
|
|
}
|