ipfs_sqlite_block_store/
error.rs1use derive_more::Display;
2use std::error::Error;
3
4#[derive(Debug, Display)]
5pub enum BlockStoreError {
6 #[display(
8 fmt = "sqlite error while {}: {} caused by {:?}",
9 _1,
10 _0,
11 "_0.source().map(std::string::ToString::to_string)"
12 )]
13 SqliteError(rusqlite::Error, &'static str),
14 #[display(fmt = "error packing a CID into fixed size: {}", _0)]
17 CidError(libipld::cid::Error),
18 #[display(
21 fmt = "DB corrupted, got unsuitable integer value while {}: {}",
22 _1,
23 _0
24 )]
25 TryFromIntError(std::num::TryFromIntError, &'static str),
26 #[display(fmt = "cannot open additional connection for in-memory DB")]
27 NoAdditionalInMemory,
28 Other(anyhow::Error),
30}
31
32impl From<anyhow::Error> for BlockStoreError {
33 fn from(v: anyhow::Error) -> Self {
34 Self::Other(v)
35 }
36}
37
38impl From<libipld::cid::Error> for BlockStoreError {
39 fn from(v: libipld::cid::Error) -> Self {
40 Self::CidError(v)
41 }
42}
43
44impl std::error::Error for BlockStoreError {
45 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
46 match self {
47 BlockStoreError::SqliteError(_e, _) => None,
48 BlockStoreError::CidError(e) => Some(e),
49 BlockStoreError::TryFromIntError(e, _) => Some(e),
50 BlockStoreError::Other(e) => AsRef::<dyn Error>::as_ref(e).source(),
51 BlockStoreError::NoAdditionalInMemory => None,
52 }
53 }
54}
55
56pub type Result<T> = std::result::Result<T, BlockStoreError>;
57
58pub(crate) trait Context {
59 type Output;
60 fn ctx(self, s: &'static str) -> Self::Output;
61}
62
63impl<T> Context for std::result::Result<T, rusqlite::Error> {
64 type Output = crate::Result<T>;
65
66 fn ctx(self, s: &'static str) -> Self::Output {
67 self.map_err(|e| BlockStoreError::SqliteError(e, s))
68 }
69}
70
71impl<T> Context for std::result::Result<T, std::num::TryFromIntError> {
72 type Output = crate::Result<T>;
73
74 fn ctx(self, s: &'static str) -> Self::Output {
75 self.map_err(|e| BlockStoreError::TryFromIntError(e, s))
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::Context;
82 use crate::BlockStoreError;
83 use anyhow::Context as _;
84
85 #[test]
86 fn show() {
87 let sqlite = std::result::Result::<(), _>::Err(rusqlite::Error::SqliteFailure(
88 rusqlite::ffi::Error::new(517),
89 Some("sql string".to_owned()),
90 ));
91
92 assert_eq!(format!("x {:?}", sqlite), "x Err(SqliteFailure(Error { code: DatabaseBusy, extended_code: 517 }, Some(\"sql string\")))");
93 if let Err(ref sqlite) = sqlite {
94 assert_eq!(format!("x {}", sqlite), "x sql string");
95 assert_eq!(format!("x {:#}", sqlite), "x sql string");
96 }
97
98 let db = sqlite.ctx("first");
99
100 assert_eq!(format!("x {:?}", db), "x Err(SqliteError(SqliteFailure(Error { code: DatabaseBusy, extended_code: 517 }, Some(\"sql string\")), \"first\"))");
101 if let Err(ref db) = db {
102 assert_eq!(
103 format!("x {}", db),
104 "x sqlite error while first: sql string caused by \
105 Some(\"Error code 517: \
106 Cannot promote read transaction to write transaction because of writes by another connection\")"
107 );
108 assert_eq!(
109 format!("x {:#}", db),
110 "x sqlite error while first: sql string caused by \
111 Some(\"Error code 517: \
112 Cannot promote read transaction to write transaction because of writes by another connection\")"
113 );
114 }
115
116 let app = db.context("second").map_err(BlockStoreError::from);
117
118 assert_eq!(
119 format!("x {:?}", app),
120 r#"x Err(Other(second
121
122Caused by:
123 sqlite error while first: sql string caused by Some("Error code 517: Cannot promote read transaction to write transaction because of writes by another connection")))"#
124 );
125 if let Err(ref app) = app {
126 assert_eq!(format!("x {}", app), "x second");
127 assert_eq!(format!("x {:#}", app), "x second: \
128 sqlite error while first: \
129 sql string caused by Some(\"Error code 517: \
130 Cannot promote read transaction to write transaction because of writes by another connection\")");
131 }
132 }
133
134 #[test]
135 fn double() {
136 let e = BlockStoreError::Other(anyhow::anyhow!("hello"));
137 assert_eq!(format!("{}", e), "hello");
138 assert_eq!(format!("{:#}", e), "hello");
139
140 let e = Result::<(), _>::Err(e).context("world").unwrap_err();
141 assert_eq!(format!("{:#}", e), "world: hello");
142
143 assert_eq!(e.to_string(), "world");
144 let e = e.source().unwrap();
145 assert_eq!(e.to_string(), "hello");
146 assert!(e.source().is_none());
147 }
148}