Skip to content

Commit

Permalink
Improve error reporting of the serde csv serializer.
Browse files Browse the repository at this point in the history
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')
  • Loading branch information
jstranik committed May 3, 2023
1 parent d24eac1 commit 6c8f858
Showing 1 changed file with 34 additions and 13 deletions.
47 changes: 34 additions & 13 deletions src/deserializer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::{error::Error as StdError, fmt, iter, num, str};

use serde::{
de::value::BorrowedBytesDeserializer,
de::{
Expand All @@ -22,11 +21,14 @@ pub fn deserialize_string_record<'de, D: Deserialize<'de>>(
record: &'de StringRecord,
headers: Option<&'de StringRecord>,
) -> Result<D, Error> {
let mut deser = DeRecordWrap(DeStringRecord {
it: record.iter().peekable(),
headers: headers.map(|r| r.iter()),
field: 0,
});
let mut deser = DeRecordWrap(
DeStringRecord {
it: record.iter().peekable(),
headers: headers.map(|r| r.iter()),
field: 0,
},
None,
);
D::deserialize(&mut deser).map_err(|err| {
Error::new(ErrorKind::Deserialize {
pos: record.position().map(Clone::clone),
Expand All @@ -39,11 +41,14 @@ pub fn deserialize_byte_record<'de, D: Deserialize<'de>>(
record: &'de ByteRecord,
headers: Option<&'de ByteRecord>,
) -> Result<D, Error> {
let mut deser = DeRecordWrap(DeByteRecord {
it: record.iter().peekable(),
headers: headers.map(|r| r.iter()),
field: 0,
});
let mut deser = DeRecordWrap(
DeByteRecord {
it: record.iter().peekable(),
headers: headers.map(|r| r.iter()),
field: 0,
},
None,
);
D::deserialize(&mut deser).map_err(|err| {
Error::new(ErrorKind::Deserialize {
pos: record.position().map(Clone::clone),
Expand Down Expand Up @@ -99,7 +104,7 @@ trait DeRecord<'r> {
) -> Result<V::Value, DeserializeError>;
}

struct DeRecordWrap<T>(T);
struct DeRecordWrap<T>(T, Option<Vec<u8>>); // inner, fieldName

impl<'r, T: DeRecord<'r>> DeRecord<'r> for DeRecordWrap<T> {
#[inline]
Expand Down Expand Up @@ -638,14 +643,30 @@ impl<'a, 'de: 'a, T: DeRecord<'de>> MapAccess<'de>
None => return Ok(None),
Some(field) => field,
};
self.1 = Some(field.to_owned());
seed.deserialize(BorrowedBytesDeserializer::new(field)).map(Some)
}

fn next_value_seed<K: DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<K::Value, Self::Error> {
seed.deserialize(&mut **self)
let field_value = self.peek_field();
seed.deserialize(&mut **self).map_err(|e| {
// enhance error with field name and field value
let DeserializeError { field, kind } = e;
DeserializeError {
field,
kind: DeserializeErrorKind::Message(format!(
"{}. (Field '{}' has a value '{}')",
kind.to_string(),
self.1.clone().map_or("".to_owned(), |x| String::from_utf8(x).unwrap()),
field_value.map_or("n/a".to_owned(), |d| {
String::from_utf8(d.to_owned()).unwrap()
})
)),
}
})
}
}

Expand Down

0 comments on commit 6c8f858

Please sign in to comment.