Skip to content

Commit 6c8f858

Browse files
committed
Improve error reporting of the serde csv serializer.
Make the error messages to show also the field and value that failed to serialize. Example of an error before the change: > Error Parsing Data: CSV deserialize error: record 1 (line: 2, byte: 549): trailing input. The new improved error message is now displayed as: > Error Parsing Data: CSV deserialize error: record 1 (line: 2, byte: 549): trailing input. (Field 'trade_timestamp' has a value '2023-04-04T09:46:45.000Z')
1 parent d24eac1 commit 6c8f858

File tree

1 file changed

+34
-13
lines changed

1 file changed

+34
-13
lines changed

src/deserializer.rs

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::{error::Error as StdError, fmt, iter, num, str};
2-
32
use serde::{
43
de::value::BorrowedBytesDeserializer,
54
de::{
@@ -22,11 +21,14 @@ pub fn deserialize_string_record<'de, D: Deserialize<'de>>(
2221
record: &'de StringRecord,
2322
headers: Option<&'de StringRecord>,
2423
) -> Result<D, Error> {
25-
let mut deser = DeRecordWrap(DeStringRecord {
26-
it: record.iter().peekable(),
27-
headers: headers.map(|r| r.iter()),
28-
field: 0,
29-
});
24+
let mut deser = DeRecordWrap(
25+
DeStringRecord {
26+
it: record.iter().peekable(),
27+
headers: headers.map(|r| r.iter()),
28+
field: 0,
29+
},
30+
None,
31+
);
3032
D::deserialize(&mut deser).map_err(|err| {
3133
Error::new(ErrorKind::Deserialize {
3234
pos: record.position().map(Clone::clone),
@@ -39,11 +41,14 @@ pub fn deserialize_byte_record<'de, D: Deserialize<'de>>(
3941
record: &'de ByteRecord,
4042
headers: Option<&'de ByteRecord>,
4143
) -> Result<D, Error> {
42-
let mut deser = DeRecordWrap(DeByteRecord {
43-
it: record.iter().peekable(),
44-
headers: headers.map(|r| r.iter()),
45-
field: 0,
46-
});
44+
let mut deser = DeRecordWrap(
45+
DeByteRecord {
46+
it: record.iter().peekable(),
47+
headers: headers.map(|r| r.iter()),
48+
field: 0,
49+
},
50+
None,
51+
);
4752
D::deserialize(&mut deser).map_err(|err| {
4853
Error::new(ErrorKind::Deserialize {
4954
pos: record.position().map(Clone::clone),
@@ -99,7 +104,7 @@ trait DeRecord<'r> {
99104
) -> Result<V::Value, DeserializeError>;
100105
}
101106

102-
struct DeRecordWrap<T>(T);
107+
struct DeRecordWrap<T>(T, Option<Vec<u8>>); // inner, fieldName
103108

104109
impl<'r, T: DeRecord<'r>> DeRecord<'r> for DeRecordWrap<T> {
105110
#[inline]
@@ -638,14 +643,30 @@ impl<'a, 'de: 'a, T: DeRecord<'de>> MapAccess<'de>
638643
None => return Ok(None),
639644
Some(field) => field,
640645
};
646+
self.1 = Some(field.to_owned());
641647
seed.deserialize(BorrowedBytesDeserializer::new(field)).map(Some)
642648
}
643649

644650
fn next_value_seed<K: DeserializeSeed<'de>>(
645651
&mut self,
646652
seed: K,
647653
) -> Result<K::Value, Self::Error> {
648-
seed.deserialize(&mut **self)
654+
let field_value = self.peek_field();
655+
seed.deserialize(&mut **self).map_err(|e| {
656+
// enhance error with field name and field value
657+
let DeserializeError { field, kind } = e;
658+
DeserializeError {
659+
field,
660+
kind: DeserializeErrorKind::Message(format!(
661+
"{}. (Field '{}' has a value '{}')",
662+
kind.to_string(),
663+
self.1.clone().map_or("".to_owned(), |x| String::from_utf8(x).unwrap()),
664+
field_value.map_or("n/a".to_owned(), |d| {
665+
String::from_utf8(d.to_owned()).unwrap()
666+
})
667+
)),
668+
}
669+
})
649670
}
650671
}
651672

0 commit comments

Comments
 (0)