1use crate::directory::DirectoryError;
12use crate::options;
13use crate::tuple::hca::HcaError;
14use crate::tuple::PackError;
15use foundationdb_sys as fdb_sys;
16use std::ffi::CStr;
17use std::fmt;
18use std::fmt::{Debug, Display, Formatter};
19
20pub(crate) fn eval(error_code: fdb_sys::fdb_error_t) -> FdbResult<()> {
21 let rust_code: i32 = error_code;
22 if rust_code == 0 {
23 Ok(())
24 } else {
25 Err(FdbError::from_code(error_code))
26 }
27}
28
29#[derive(Debug, Copy, Clone)]
31pub struct FdbError {
32 error_code: i32,
34}
35
36impl FdbError {
37 pub fn from_code(error_code: fdb_sys::fdb_error_t) -> Self {
39 Self { error_code }
40 }
41
42 #[cfg(feature = "tenant-experimental")]
43 pub(crate) fn new(error_code: i32) -> Self {
45 Self { error_code }
46 }
47
48 pub fn message(self) -> &'static str {
49 let error_str =
50 unsafe { CStr::from_ptr::<'static>(fdb_sys::fdb_get_error(self.error_code)) };
51 error_str
52 .to_str()
53 .expect("bad error string from FoundationDB")
54 }
55
56 fn is_error_predicate(self, predicate: options::ErrorPredicate) -> bool {
57 #[allow(clippy::unnecessary_cast)]
59 let check =
60 unsafe { fdb_sys::fdb_error_predicate(predicate.code() as i32, self.error_code) };
61
62 check != 0
63 }
64
65 pub fn is_maybe_committed(self) -> bool {
67 self.is_error_predicate(options::ErrorPredicate::MaybeCommitted)
68 }
69
70 pub fn is_retryable(self) -> bool {
72 self.is_error_predicate(options::ErrorPredicate::Retryable)
73 }
74
75 pub fn is_retryable_not_committed(self) -> bool {
77 self.is_error_predicate(options::ErrorPredicate::RetryableNotCommitted)
78 }
79
80 pub fn code(self) -> i32 {
82 self.error_code
83 }
84}
85
86impl fmt::Display for FdbError {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 std::fmt::Display::fmt(&self.message(), f)
89 }
90}
91
92impl std::error::Error for FdbError {}
93
94pub type FdbResult<T = ()> = Result<T, FdbError>;
96
97pub enum FdbBindingError {
100 NonRetryableFdbError(FdbError),
101 HcaError(HcaError),
102 DirectoryError(DirectoryError),
103 PackError(PackError),
104 ReferenceToTransactionKept,
106 CustomError(Box<dyn std::error::Error + Send + Sync>),
108}
109
110impl FdbBindingError {
111 pub fn get_fdb_error(&self) -> Option<FdbError> {
113 match *self {
114 Self::NonRetryableFdbError(error)
115 | Self::DirectoryError(DirectoryError::FdbError(error))
116 | Self::HcaError(HcaError::FdbError(error)) => Some(error),
117 Self::CustomError(ref error) => {
118 if let Some(e) = error.downcast_ref::<FdbError>() {
119 Some(*e)
120 } else if let Some(e) = error.downcast_ref::<FdbBindingError>() {
121 e.get_fdb_error()
122 } else {
123 None
124 }
125 }
126 _ => None,
127 }
128 }
129}
130
131impl From<FdbError> for FdbBindingError {
132 fn from(e: FdbError) -> Self {
133 Self::NonRetryableFdbError(e)
134 }
135}
136
137impl From<HcaError> for FdbBindingError {
138 fn from(e: HcaError) -> Self {
139 Self::HcaError(e)
140 }
141}
142
143impl From<DirectoryError> for FdbBindingError {
144 fn from(e: DirectoryError) -> Self {
145 Self::DirectoryError(e)
146 }
147}
148
149impl FdbBindingError {
150 pub fn new_custom_error(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
152 Self::CustomError(e)
153 }
154}
155
156impl Debug for FdbBindingError {
157 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158 match self {
159 FdbBindingError::NonRetryableFdbError(err) => write!(f, "{err:?}"),
160 FdbBindingError::HcaError(err) => write!(f, "{err:?}"),
161 FdbBindingError::DirectoryError(err) => write!(f, "{err:?}"),
162 FdbBindingError::PackError(err) => write!(f, "{err:?}"),
163 FdbBindingError::ReferenceToTransactionKept => {
164 write!(f, "Reference to transaction kept")
165 }
166 FdbBindingError::CustomError(err) => write!(f, "{err:?}"),
167 }
168 }
169}
170
171impl Display for FdbBindingError {
172 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173 std::fmt::Debug::fmt(&self, f)
174 }
175}
176
177impl std::error::Error for FdbBindingError {}