1use crate::prelude::DbKey;
2use kaspa_hashes::Hash;
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum StoreError {
7 #[error("key {0} not found in store")]
8 KeyNotFound(DbKey),
9
10 #[error("key {0} already exists in store")]
11 KeyAlreadyExists(String),
12
13 #[error("hash {0} already exists in store")]
16 HashAlreadyExists(Hash),
17
18 #[error("data inconsistency: {0}")]
19 DataInconsistency(String),
20
21 #[error("rocksdb error {0}")]
22 DbError(#[from] rocksdb::Error),
23
24 #[error("bincode error {0}")]
25 DeserializationError(#[from] Box<bincode::ErrorKind>),
26}
27
28pub type StoreResult<T> = std::result::Result<T, StoreError>;
29
30pub trait StoreErrorPredicates {
35 fn is_key_not_found(&self) -> bool;
37
38 fn is_already_exists(&self) -> bool;
40}
41
42impl StoreErrorPredicates for StoreError {
43 fn is_key_not_found(&self) -> bool {
44 matches!(self, StoreError::KeyNotFound(_))
45 }
46
47 fn is_already_exists(&self) -> bool {
48 matches!(self, StoreError::KeyAlreadyExists(_) | StoreError::HashAlreadyExists(_))
49 }
50}
51
52pub trait StoreResultExt<T, E: StoreErrorPredicates> {
54 fn optional(self) -> Result<Option<T>, E>;
63}
64
65impl<T, E: StoreErrorPredicates> StoreResultExt<T, E> for Result<T, E> {
66 fn optional(self) -> Result<Option<T>, E> {
67 match self {
68 Ok(value) => Ok(Some(value)),
69 Err(err) if err.is_key_not_found() => Ok(None),
70 Err(err) => Err(err),
71 }
72 }
73}
74
75pub trait StoreResultUnitExt<E: StoreErrorPredicates> {
77 fn idempotent(self) -> Result<(), E>;
86}
87
88impl<E: StoreErrorPredicates> StoreResultUnitExt<E> for Result<(), E> {
89 fn idempotent(self) -> Result<(), E> {
90 match self {
91 Ok(()) => Ok(()),
92 Err(err) if err.is_already_exists() => Ok(()),
93 Err(err) => Err(err),
94 }
95 }
96}