Anki/rslib/src/error/not_found.rs
Damien Elmes fa625d7ad8
Minor Rust cleanups (#2272)
* 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.
2022-12-16 21:40:27 +10:00

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");
}
}