mirror of
https://github.com/ankitects/anki.git
synced 2025-11-09 22:27:12 -05:00
* Run cargo +nightly fmt * Latest prost-build includes clippy workaround * Tweak Rust protobuf imports - Avoid use of stringify!(), as JetBrains editors get confused by it - Stop merging all protobuf symbols into a single namespace * Remove some unnecessary qualifications Found via IntelliJ lint * Migrate some asserts to assert_eq/ne * Remove mention of node_modules exclusion This no longer seems to be necessary after migrating away from Bazel, and excluding it means TS/Svelte files can't be edited properly.
72 lines
1.8 KiB
Rust
72 lines
1.8 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use std::{any, fmt};
|
|
|
|
use convert_case::{Case, Casing};
|
|
use snafu::{Backtrace, OptionExt, Snafu};
|
|
|
|
use crate::prelude::*;
|
|
|
|
/// Something was unexpectedly missing from the database.
|
|
#[derive(Debug, Snafu)]
|
|
#[snafu(visibility(pub))]
|
|
pub struct NotFoundError {
|
|
pub type_name: String,
|
|
pub identifier: String,
|
|
pub backtrace: Option<Backtrace>,
|
|
}
|
|
|
|
impl NotFoundError {
|
|
pub fn message(&self, tr: &I18n) -> String {
|
|
tr.errors_inconsistent_db_state().into()
|
|
}
|
|
|
|
pub fn context(&self) -> String {
|
|
format!("No such {}: '{}'", self.type_name, self.identifier)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for NotFoundError {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.type_name == other.type_name && self.identifier == other.identifier
|
|
}
|
|
}
|
|
|
|
impl Eq for NotFoundError {}
|
|
|
|
/// Allows generating [AnkiError::NotFound] from [None].
|
|
pub trait OrNotFound {
|
|
type Value;
|
|
fn or_not_found(self, identifier: impl fmt::Display) -> Result<Self::Value>;
|
|
}
|
|
|
|
impl<T> OrNotFound for Option<T> {
|
|
type Value = T;
|
|
|
|
fn or_not_found(self, identifier: impl fmt::Display) -> Result<Self::Value> {
|
|
self.with_context(|| NotFoundSnafu {
|
|
type_name: unqualified_lowercase_type_name::<Self::Value>(),
|
|
identifier: format!("{identifier}"),
|
|
})
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
fn unqualified_lowercase_type_name<T: ?Sized>() -> String {
|
|
any::type_name::<T>()
|
|
.split("::")
|
|
.last()
|
|
.unwrap_or_default()
|
|
.to_case(Case::Lower)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_unqualified_lowercase_type_name() {
|
|
assert_eq!(unqualified_lowercase_type_name::<CardId>(), "card id");
|
|
}
|
|
}
|