1use std::{any, fmt::Display, ops::Deref};
2
3pub type _Backtrace = std::backtrace::Backtrace;
8
9#[derive(thiserror::Error)]
10pub enum SerializationError {
11 #[error("Failed to serialize {location:?}")]
12 Context {
13 location: String,
14 source: Box<SerializationError>,
15 },
16
17 #[error("Trying to serialize a field lacking extension metadata: {fqname:?}")]
18 MissingExtensionMetadata {
19 fqname: String,
20 backtrace: Box<_Backtrace>,
21 },
22
23 #[error("{fqname} doesn't support Serialization: {reason}")]
24 NotImplemented {
25 fqname: String,
26 reason: String,
27 backtrace: Box<_Backtrace>,
28 },
29
30 #[error(transparent)]
32 ArrowError(#[from] ArcArrowError),
33}
34
35#[test]
36fn test_serialization_error_size() {
37 assert!(
38 std::mem::size_of::<SerializationError>() <= 64,
39 "Size of error is {} bytes. Let's try to keep errors small.",
40 std::mem::size_of::<SerializationError>()
41 );
42}
43
44impl std::fmt::Debug for SerializationError {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 if let Some(backtrace) = self.backtrace() {
47 f.write_fmt(format_args!("{self}:\n{backtrace:#?}"))
48 } else {
49 f.write_fmt(format_args!("{self}"))
50 }
51 }
52}
53
54impl SerializationError {
55 #[inline]
56 pub fn missing_extension_metadata(fqname: impl AsRef<str>) -> Self {
57 Self::MissingExtensionMetadata {
58 fqname: fqname.as_ref().into(),
59 backtrace: Box::new(std::backtrace::Backtrace::capture()),
60 }
61 }
62
63 #[inline]
64 pub fn not_implemented(fqname: impl AsRef<str>, reason: impl AsRef<str>) -> Self {
65 Self::NotImplemented {
66 fqname: fqname.as_ref().into(),
67 reason: reason.as_ref().into(),
68 backtrace: Box::new(std::backtrace::Backtrace::capture()),
69 }
70 }
71
72 pub fn backtrace(&self) -> Option<&_Backtrace> {
76 match self {
77 Self::MissingExtensionMetadata { backtrace, .. }
78 | Self::NotImplemented { backtrace, .. } => Some(backtrace),
79 Self::ArrowError { .. } | Self::Context { .. } => None,
80 }
81 }
82}
83
84#[derive(Clone, Debug)]
92pub struct ArcArrowError(std::sync::Arc<arrow::error::ArrowError>);
93
94impl From<arrow::error::ArrowError> for ArcArrowError {
95 fn from(e: arrow::error::ArrowError) -> Self {
96 Self(std::sync::Arc::new(e))
97 }
98}
99
100impl From<arrow::error::ArrowError> for SerializationError {
101 fn from(e: arrow::error::ArrowError) -> Self {
102 Self::ArrowError(ArcArrowError::from(e))
103 }
104}
105
106impl Deref for ArcArrowError {
107 type Target = arrow::error::ArrowError;
108
109 #[inline]
110 fn deref(&self) -> &Self::Target {
111 self.0.as_ref()
112 }
113}
114
115impl Display for ArcArrowError {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 self.0.fmt(f)
118 }
119}
120
121pub type SerializationResult<T> = ::std::result::Result<T, SerializationError>;
124
125#[derive(thiserror::Error)]
128pub enum DeserializationError {
129 #[error("Failed to deserialize {location:?}")]
130 Context {
131 location: String,
132 #[source]
133 source: Box<DeserializationError>,
134 },
135
136 #[error("{fqname} doesn't support deserialization")]
137 NotImplemented {
138 fqname: String,
139 backtrace: Box<_Backtrace>,
140 },
141
142 #[error("Expected non-nullable data but didn't find any")]
143 MissingData { backtrace: Box<_Backtrace> },
144
145 #[error("Expected field {field_name:?} to be present in {datatype}")]
146 MissingStructField {
147 datatype: arrow::datatypes::DataType,
148 field_name: String,
149 backtrace: Box<_Backtrace>,
150 },
151
152 #[error(
153 "Found {field1_length} {field1_name:?} values vs. {field2_length} {field2_name:?} values"
154 )]
155 MismatchedStructFieldLengths {
156 field1_name: String,
157 field1_length: usize,
158 field2_name: String,
159 field2_length: usize,
160 backtrace: Box<_Backtrace>,
161 },
162
163 #[error("Expected union arm {arm_name:?} (#{arm_index}) to be present in {datatype}")]
164 MissingUnionArm {
165 datatype: arrow::datatypes::DataType,
166 arm_name: String,
167 arm_index: usize,
168 backtrace: Box<_Backtrace>,
169 },
170
171 #[error("Expected {expected} but found {got} instead")]
172 DatatypeMismatch {
173 expected: arrow::datatypes::DataType,
174 got: arrow::datatypes::DataType,
175 backtrace: Box<_Backtrace>,
176 },
177
178 #[error("Offset ouf of bounds: trying to read at offset #{offset} in an array of size {len}")]
179 OffsetOutOfBounds {
180 offset: usize,
181 len: usize,
182 backtrace: Box<_Backtrace>,
183 },
184
185 #[error(
186 "Offset slice ouf of bounds: trying to read offset slice at [#{from}..#{to}] in an array of size {len}"
187 )]
188 OffsetSliceOutOfBounds {
189 from: usize,
190 to: usize,
191 len: usize,
192 backtrace: Box<_Backtrace>,
193 },
194
195 #[error("Downcast to {to} failed")]
196 DowncastError {
197 to: String,
198 backtrace: Box<_Backtrace>,
199 },
200
201 #[error("Datacell deserialization Failed: {0}")]
202 DataCellError(String),
203
204 #[error("Validation Error: {0}")]
205 ValidationError(String),
206}
207
208#[test]
209fn test_derserialization_error_size() {
210 assert!(
211 std::mem::size_of::<DeserializationError>() <= 72,
212 "Size of error is {} bytes. Let's try to keep errors small.",
213 std::mem::size_of::<DeserializationError>()
214 );
215}
216
217impl std::fmt::Debug for DeserializationError {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 if let Some(backtrace) = self.backtrace() {
220 f.write_fmt(format_args!("{self}:\n{backtrace:#?}"))
221 } else {
222 f.write_fmt(format_args!("{self}"))
223 }
224 }
225}
226
227impl DeserializationError {
228 #[inline]
229 pub fn missing_data() -> Self {
230 Self::MissingData {
231 backtrace: Box::new(std::backtrace::Backtrace::capture()),
232 }
233 }
234
235 #[inline]
236 pub fn missing_struct_field(
237 datatype: impl Into<arrow::datatypes::DataType>,
238 field_name: impl AsRef<str>,
239 ) -> Self {
240 Self::MissingStructField {
241 datatype: datatype.into(),
242 field_name: field_name.as_ref().into(),
243 backtrace: Box::new(std::backtrace::Backtrace::capture()),
244 }
245 }
246
247 #[inline]
248 pub fn mismatched_struct_field_lengths(
249 field1_name: impl AsRef<str>,
250 field1_length: usize,
251 field2_name: impl AsRef<str>,
252 field2_length: usize,
253 ) -> Self {
254 Self::MismatchedStructFieldLengths {
255 field1_name: field1_name.as_ref().into(),
256 field1_length,
257 field2_name: field2_name.as_ref().into(),
258 field2_length,
259 backtrace: Box::new(std::backtrace::Backtrace::capture()),
260 }
261 }
262
263 #[inline]
264 pub fn missing_union_arm(
265 datatype: impl Into<arrow::datatypes::DataType>,
266 arm_name: impl AsRef<str>,
267 arm_index: usize,
268 ) -> Self {
269 Self::MissingUnionArm {
270 datatype: datatype.into(),
271 arm_name: arm_name.as_ref().into(),
272 arm_index,
273 backtrace: Box::new(std::backtrace::Backtrace::capture()),
274 }
275 }
276
277 #[inline]
278 pub fn datatype_mismatch(
279 expected: impl Into<arrow::datatypes::DataType>,
280 got: impl Into<arrow::datatypes::DataType>,
281 ) -> Self {
282 Self::DatatypeMismatch {
283 expected: expected.into(),
284 got: got.into(),
285 backtrace: Box::new(std::backtrace::Backtrace::capture()),
286 }
287 }
288
289 #[inline]
290 pub fn offset_oob(offset: usize, len: usize) -> Self {
291 Self::OffsetOutOfBounds {
292 offset,
293 len,
294 backtrace: Box::new(std::backtrace::Backtrace::capture()),
295 }
296 }
297
298 #[inline]
299 pub fn offset_slice_oob((from, to): (usize, usize), len: usize) -> Self {
300 Self::OffsetSliceOutOfBounds {
301 from,
302 to,
303 len,
304 backtrace: Box::new(std::backtrace::Backtrace::capture()),
305 }
306 }
307
308 #[inline]
309 pub fn downcast_error<ToType>() -> Self {
310 Self::DowncastError {
311 to: any::type_name::<ToType>().to_owned(),
312 backtrace: Box::new(std::backtrace::Backtrace::capture()),
313 }
314 }
315
316 #[inline]
320 pub fn backtrace(&self) -> Option<&_Backtrace> {
321 match self {
322 Self::Context {
323 location: _,
324 source,
325 } => source.backtrace(),
326 Self::NotImplemented { backtrace, .. }
327 | Self::MissingStructField { backtrace, .. }
328 | Self::MismatchedStructFieldLengths { backtrace, .. }
329 | Self::MissingUnionArm { backtrace, .. }
330 | Self::MissingData { backtrace }
331 | Self::DatatypeMismatch { backtrace, .. }
332 | Self::OffsetOutOfBounds { backtrace, .. }
333 | Self::OffsetSliceOutOfBounds { backtrace, .. }
334 | Self::DowncastError { backtrace, .. } => Some(backtrace),
335 Self::DataCellError(_) | Self::ValidationError(_) => None,
336 }
337 }
338
339 pub fn without_context(self) -> Self {
341 match self {
342 Self::Context { source, .. } => source.without_context(),
343 _ => self,
344 }
345 }
346}
347
348pub type DeserializationResult<T> = ::std::result::Result<T, DeserializationError>;
349
350pub trait ResultExt<T> {
351 fn with_context(self, location: impl AsRef<str>) -> Self;
352}
353
354impl<T> ResultExt<T> for SerializationResult<T> {
355 #[inline]
356 fn with_context(self, location: impl AsRef<str>) -> Self {
357 self.map_err(|err| SerializationError::Context {
358 location: location.as_ref().into(),
359 source: Box::new(err),
360 })
361 }
362}
363
364impl<T> ResultExt<T> for DeserializationResult<T> {
365 #[inline]
366 fn with_context(self, location: impl AsRef<str>) -> Self {
367 self.map_err(|err| DeserializationError::Context {
368 location: location.as_ref().into(),
369 source: Box::new(err),
370 })
371 }
372}