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 pub(crate) fn new(error_code: i32) -> Self {
43 Self { error_code }
44 }
45
46 pub fn message(self) -> &'static str {
47 let error_str =
48 unsafe { CStr::from_ptr::<'static>(fdb_sys::fdb_get_error(self.error_code)) };
49 error_str
50 .to_str()
51 .expect("bad error string from FoundationDB")
52 }
53
54 fn is_error_predicate(self, predicate: options::ErrorPredicate) -> bool {
55 #[allow(clippy::unnecessary_cast)]
57 let check =
58 unsafe { fdb_sys::fdb_error_predicate(predicate.code() as i32, self.error_code) };
59
60 check != 0
61 }
62
63 pub fn is_maybe_committed(self) -> bool {
65 self.is_error_predicate(options::ErrorPredicate::MaybeCommitted)
66 }
67
68 pub fn is_retryable(self) -> bool {
70 self.is_error_predicate(options::ErrorPredicate::Retryable)
71 }
72
73 pub fn is_retryable_not_committed(self) -> bool {
75 self.is_error_predicate(options::ErrorPredicate::RetryableNotCommitted)
76 }
77
78 pub fn code(self) -> i32 {
80 self.error_code
81 }
82}
83
84impl fmt::Display for FdbError {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 std::fmt::Display::fmt(&self.message(), f)
87 }
88}
89
90impl std::error::Error for FdbError {}
91
92pub type FdbResult<T = ()> = Result<T, FdbError>;
94
95pub enum FdbBindingError {
98 NonRetryableFdbError(FdbError),
99 HcaError(HcaError),
100 DirectoryError(DirectoryError),
101 PackError(PackError),
102 ReferenceToTransactionKept,
104 CustomError(Box<dyn std::error::Error + Send + Sync>),
106}
107
108impl FdbBindingError {
109 pub fn get_fdb_error(&self) -> Option<FdbError> {
111 match *self {
112 Self::NonRetryableFdbError(error)
113 | Self::DirectoryError(DirectoryError::FdbError(error))
114 | Self::HcaError(HcaError::FdbError(error)) => Some(error),
115 Self::CustomError(ref error) => {
116 if let Some(e) = error.downcast_ref::<FdbError>() {
117 Some(*e)
118 } else if let Some(e) = error.downcast_ref::<FdbBindingError>() {
119 e.get_fdb_error()
120 } else {
121 None
122 }
123 }
124 _ => None,
125 }
126 }
127}
128
129impl From<FdbError> for FdbBindingError {
130 fn from(e: FdbError) -> Self {
131 Self::NonRetryableFdbError(e)
132 }
133}
134
135impl From<HcaError> for FdbBindingError {
136 fn from(e: HcaError) -> Self {
137 Self::HcaError(e)
138 }
139}
140
141impl From<DirectoryError> for FdbBindingError {
142 fn from(e: DirectoryError) -> Self {
143 Self::DirectoryError(e)
144 }
145}
146
147impl FdbBindingError {
148 pub fn new_custom_error(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
150 Self::CustomError(e)
151 }
152}
153
154impl Debug for FdbBindingError {
155 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156 match self {
157 FdbBindingError::NonRetryableFdbError(err) => write!(f, "{:?}", err),
158 FdbBindingError::HcaError(err) => write!(f, "{:?}", err),
159 FdbBindingError::DirectoryError(err) => write!(f, "{:?}", err),
160 FdbBindingError::PackError(err) => write!(f, "{:?}", err),
161 FdbBindingError::ReferenceToTransactionKept => {
162 write!(f, "Reference to transaction kept")
163 }
164 FdbBindingError::CustomError(err) => write!(f, "{:?}", err),
165 }
166 }
167}
168
169impl Display for FdbBindingError {
170 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
171 std::fmt::Debug::fmt(&self, f)
172 }
173}
174
175impl std::error::Error for FdbBindingError {}