| use std::error::Error as StdError; |
| use std::fmt; |
| use std::iter; |
| use std::num; |
| use std::str; |
| |
| use serde::de::value::BorrowedBytesDeserializer; |
| use serde::de::{ |
| Deserialize, DeserializeSeed, Deserializer, EnumAccess, |
| Error as SerdeError, IntoDeserializer, MapAccess, SeqAccess, Unexpected, |
| VariantAccess, Visitor, |
| }; |
| use serde::serde_if_integer128; |
| |
| use crate::byte_record::{ByteRecord, ByteRecordIter}; |
| use crate::error::{Error, ErrorKind}; |
| use crate::string_record::{StringRecord, StringRecordIter}; |
| |
| use self::DeserializeErrorKind as DEK; |
| |
| 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, |
| }); |
| D::deserialize(&mut deser).map_err(|err| { |
| Error::new(ErrorKind::Deserialize { |
| pos: record.position().map(Clone::clone), |
| err: err, |
| }) |
| }) |
| } |
| |
| 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, |
| }); |
| D::deserialize(&mut deser).map_err(|err| { |
| Error::new(ErrorKind::Deserialize { |
| pos: record.position().map(Clone::clone), |
| err: err, |
| }) |
| }) |
| } |
| |
| /// An over-engineered internal trait that permits writing a single Serde |
| /// deserializer that works on both ByteRecord and StringRecord. |
| /// |
| /// We *could* implement a single deserializer on `ByteRecord` and simply |
| /// convert `StringRecord`s to `ByteRecord`s, but then the implementation |
| /// would be required to redo UTF-8 validation checks in certain places. |
| /// |
| /// How does this work? We create a new `DeRecordWrap` type that wraps |
| /// either a `StringRecord` or a `ByteRecord`. We then implement |
| /// `DeRecord` for `DeRecordWrap<ByteRecord>` and `DeRecordWrap<StringRecord>`. |
| /// Finally, we impl `serde::Deserialize` for `DeRecordWrap<T>` where |
| /// `T: DeRecord`. That is, the `DeRecord` type corresponds to the differences |
| /// between deserializing into a `ByteRecord` and deserializing into a |
| /// `StringRecord`. |
| /// |
| /// The lifetime `'r` refers to the lifetime of the underlying record. |
| trait DeRecord<'r> { |
| /// Returns true if and only if this deserialize has access to headers. |
| fn has_headers(&self) -> bool; |
| |
| /// Extracts the next string header value from the underlying record. |
| fn next_header(&mut self) -> Result<Option<&'r str>, DeserializeError>; |
| |
| /// Extracts the next raw byte header value from the underlying record. |
| fn next_header_bytes( |
| &mut self, |
| ) -> Result<Option<&'r [u8]>, DeserializeError>; |
| |
| /// Extracts the next string field from the underlying record. |
| fn next_field(&mut self) -> Result<&'r str, DeserializeError>; |
| |
| /// Extracts the next raw byte field from the underlying record. |
| fn next_field_bytes(&mut self) -> Result<&'r [u8], DeserializeError>; |
| |
| /// Peeks at the next field from the underlying record. |
| fn peek_field(&mut self) -> Option<&'r [u8]>; |
| |
| /// Returns an error corresponding to the most recently extracted field. |
| fn error(&self, kind: DeserializeErrorKind) -> DeserializeError; |
| |
| /// Infer the type of the next field and deserialize it. |
| fn infer_deserialize<'de, V: Visitor<'de>>( |
| &mut self, |
| visitor: V, |
| ) -> Result<V::Value, DeserializeError>; |
| } |
| |
| struct DeRecordWrap<T>(T); |
| |
| impl<'r, T: DeRecord<'r>> DeRecord<'r> for DeRecordWrap<T> { |
| #[inline] |
| fn has_headers(&self) -> bool { |
| self.0.has_headers() |
| } |
| |
| #[inline] |
| fn next_header(&mut self) -> Result<Option<&'r str>, DeserializeError> { |
| self.0.next_header() |
| } |
| |
| #[inline] |
| fn next_header_bytes( |
| &mut self, |
| ) -> Result<Option<&'r [u8]>, DeserializeError> { |
| self.0.next_header_bytes() |
| } |
| |
| #[inline] |
| fn next_field(&mut self) -> Result<&'r str, DeserializeError> { |
| self.0.next_field() |
| } |
| |
| #[inline] |
| fn next_field_bytes(&mut self) -> Result<&'r [u8], DeserializeError> { |
| self.0.next_field_bytes() |
| } |
| |
| #[inline] |
| fn peek_field(&mut self) -> Option<&'r [u8]> { |
| self.0.peek_field() |
| } |
| |
| #[inline] |
| fn error(&self, kind: DeserializeErrorKind) -> DeserializeError { |
| self.0.error(kind) |
| } |
| |
| #[inline] |
| fn infer_deserialize<'de, V: Visitor<'de>>( |
| &mut self, |
| visitor: V, |
| ) -> Result<V::Value, DeserializeError> { |
| self.0.infer_deserialize(visitor) |
| } |
| } |
| |
| struct DeStringRecord<'r> { |
| it: iter::Peekable<StringRecordIter<'r>>, |
| headers: Option<StringRecordIter<'r>>, |
| field: u64, |
| } |
| |
| impl<'r> DeRecord<'r> for DeStringRecord<'r> { |
| #[inline] |
| fn has_headers(&self) -> bool { |
| self.headers.is_some() |
| } |
| |
| #[inline] |
| fn next_header(&mut self) -> Result<Option<&'r str>, DeserializeError> { |
| Ok(self.headers.as_mut().and_then(|it| it.next())) |
| } |
| |
| #[inline] |
| fn next_header_bytes( |
| &mut self, |
| ) -> Result<Option<&'r [u8]>, DeserializeError> { |
| Ok(self.next_header()?.map(|s| s.as_bytes())) |
| } |
| |
| #[inline] |
| fn next_field(&mut self) -> Result<&'r str, DeserializeError> { |
| match self.it.next() { |
| Some(field) => { |
| self.field += 1; |
| Ok(field) |
| } |
| None => Err(DeserializeError { |
| field: None, |
| kind: DEK::UnexpectedEndOfRow, |
| }), |
| } |
| } |
| |
| #[inline] |
| fn next_field_bytes(&mut self) -> Result<&'r [u8], DeserializeError> { |
| self.next_field().map(|s| s.as_bytes()) |
| } |
| |
| #[inline] |
| fn peek_field(&mut self) -> Option<&'r [u8]> { |
| self.it.peek().map(|s| s.as_bytes()) |
| } |
| |
| fn error(&self, kind: DeserializeErrorKind) -> DeserializeError { |
| DeserializeError { |
| field: Some(self.field.saturating_sub(1)), |
| kind: kind, |
| } |
| } |
| |
| fn infer_deserialize<'de, V: Visitor<'de>>( |
| &mut self, |
| visitor: V, |
| ) -> Result<V::Value, DeserializeError> { |
| let x = self.next_field()?; |
| if x == "true" { |
| return visitor.visit_bool(true); |
| } else if x == "false" { |
| return visitor.visit_bool(false); |
| } else if let Some(n) = try_positive_integer64(x) { |
| return visitor.visit_u64(n); |
| } else if let Some(n) = try_negative_integer64(x) { |
| return visitor.visit_i64(n); |
| } |
| serde_if_integer128! { |
| if let Some(n) = try_positive_integer128(x) { |
| return visitor.visit_u128(n); |
| } else if let Some(n) = try_negative_integer128(x) { |
| return visitor.visit_i128(n); |
| } |
| } |
| if let Some(n) = try_float(x) { |
| visitor.visit_f64(n) |
| } else { |
| visitor.visit_str(x) |
| } |
| } |
| } |
| |
| struct DeByteRecord<'r> { |
| it: iter::Peekable<ByteRecordIter<'r>>, |
| headers: Option<ByteRecordIter<'r>>, |
| field: u64, |
| } |
| |
| impl<'r> DeRecord<'r> for DeByteRecord<'r> { |
| #[inline] |
| fn has_headers(&self) -> bool { |
| self.headers.is_some() |
| } |
| |
| #[inline] |
| fn next_header(&mut self) -> Result<Option<&'r str>, DeserializeError> { |
| match self.next_header_bytes() { |
| Ok(Some(field)) => Ok(Some( |
| str::from_utf8(field) |
| .map_err(|err| self.error(DEK::InvalidUtf8(err)))?, |
| )), |
| Ok(None) => Ok(None), |
| Err(err) => Err(err), |
| } |
| } |
| |
| #[inline] |
| fn next_header_bytes( |
| &mut self, |
| ) -> Result<Option<&'r [u8]>, DeserializeError> { |
| Ok(self.headers.as_mut().and_then(|it| it.next())) |
| } |
| |
| #[inline] |
| fn next_field(&mut self) -> Result<&'r str, DeserializeError> { |
| self.next_field_bytes().and_then(|field| { |
| str::from_utf8(field) |
| .map_err(|err| self.error(DEK::InvalidUtf8(err))) |
| }) |
| } |
| |
| #[inline] |
| fn next_field_bytes(&mut self) -> Result<&'r [u8], DeserializeError> { |
| match self.it.next() { |
| Some(field) => { |
| self.field += 1; |
| Ok(field) |
| } |
| None => Err(DeserializeError { |
| field: None, |
| kind: DEK::UnexpectedEndOfRow, |
| }), |
| } |
| } |
| |
| #[inline] |
| fn peek_field(&mut self) -> Option<&'r [u8]> { |
| self.it.peek().map(|s| *s) |
| } |
| |
| fn error(&self, kind: DeserializeErrorKind) -> DeserializeError { |
| DeserializeError { |
| field: Some(self.field.saturating_sub(1)), |
| kind: kind, |
| } |
| } |
| |
| fn infer_deserialize<'de, V: Visitor<'de>>( |
| &mut self, |
| visitor: V, |
| ) -> Result<V::Value, DeserializeError> { |
| let x = self.next_field_bytes()?; |
| if x == b"true" { |
| return visitor.visit_bool(true); |
| } else if x == b"false" { |
| return visitor.visit_bool(false); |
| } else if let Some(n) = try_positive_integer64_bytes(x) { |
| return visitor.visit_u64(n); |
| } else if let Some(n) = try_negative_integer64_bytes(x) { |
| return visitor.visit_i64(n); |
| } |
| serde_if_integer128! { |
| if let Some(n) = try_positive_integer128_bytes(x) { |
| return visitor.visit_u128(n); |
| } else if let Some(n) = try_negative_integer128_bytes(x) { |
| return visitor.visit_i128(n); |
| } |
| } |
| if let Some(n) = try_float_bytes(x) { |
| visitor.visit_f64(n) |
| } else if let Ok(s) = str::from_utf8(x) { |
| visitor.visit_str(s) |
| } else { |
| visitor.visit_bytes(x) |
| } |
| } |
| } |
| |
| macro_rules! deserialize_int { |
| ($method:ident, $visit:ident, $inttype:ty) => { |
| fn $method<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| let field = self.next_field()?; |
| let num = if field.starts_with("0x") { |
| <$inttype>::from_str_radix(&field[2..], 16) |
| } else { |
| field.parse() |
| }; |
| visitor.$visit(num.map_err(|err| self.error(DEK::ParseInt(err)))?) |
| } |
| }; |
| } |
| |
| impl<'a, 'de: 'a, T: DeRecord<'de>> Deserializer<'de> |
| for &'a mut DeRecordWrap<T> |
| { |
| type Error = DeserializeError; |
| |
| fn deserialize_any<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| self.infer_deserialize(visitor) |
| } |
| |
| fn deserialize_bool<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_bool( |
| self.next_field()? |
| .parse() |
| .map_err(|err| self.error(DEK::ParseBool(err)))?, |
| ) |
| } |
| |
| deserialize_int!(deserialize_u8, visit_u8, u8); |
| deserialize_int!(deserialize_u16, visit_u16, u16); |
| deserialize_int!(deserialize_u32, visit_u32, u32); |
| deserialize_int!(deserialize_u64, visit_u64, u64); |
| serde_if_integer128! { |
| deserialize_int!(deserialize_u128, visit_u128, u128); |
| } |
| deserialize_int!(deserialize_i8, visit_i8, i8); |
| deserialize_int!(deserialize_i16, visit_i16, i16); |
| deserialize_int!(deserialize_i32, visit_i32, i32); |
| deserialize_int!(deserialize_i64, visit_i64, i64); |
| serde_if_integer128! { |
| deserialize_int!(deserialize_i128, visit_i128, i128); |
| } |
| |
| fn deserialize_f32<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_f32( |
| self.next_field()? |
| .parse() |
| .map_err(|err| self.error(DEK::ParseFloat(err)))?, |
| ) |
| } |
| |
| fn deserialize_f64<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_f64( |
| self.next_field()? |
| .parse() |
| .map_err(|err| self.error(DEK::ParseFloat(err)))?, |
| ) |
| } |
| |
| fn deserialize_char<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| let field = self.next_field()?; |
| let len = field.chars().count(); |
| if len != 1 { |
| return Err(self.error(DEK::Message(format!( |
| "expected single character but got {} characters in '{}'", |
| len, field |
| )))); |
| } |
| visitor.visit_char(field.chars().next().unwrap()) |
| } |
| |
| fn deserialize_str<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| self.next_field().and_then(|f| visitor.visit_borrowed_str(f)) |
| } |
| |
| fn deserialize_string<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| self.next_field().and_then(|f| visitor.visit_str(f.into())) |
| } |
| |
| fn deserialize_bytes<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| self.next_field_bytes().and_then(|f| visitor.visit_borrowed_bytes(f)) |
| } |
| |
| fn deserialize_byte_buf<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| self.next_field_bytes() |
| .and_then(|f| visitor.visit_byte_buf(f.to_vec())) |
| } |
| |
| fn deserialize_option<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| match self.peek_field() { |
| None => visitor.visit_none(), |
| Some(f) if f.is_empty() => { |
| self.next_field().expect("empty field"); |
| visitor.visit_none() |
| } |
| Some(_) => visitor.visit_some(self), |
| } |
| } |
| |
| fn deserialize_unit<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_unit() |
| } |
| |
| fn deserialize_unit_struct<V: Visitor<'de>>( |
| self, |
| _name: &'static str, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_unit() |
| } |
| |
| fn deserialize_newtype_struct<V: Visitor<'de>>( |
| self, |
| _name: &'static str, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_newtype_struct(self) |
| } |
| |
| fn deserialize_seq<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_seq(self) |
| } |
| |
| fn deserialize_tuple<V: Visitor<'de>>( |
| self, |
| _len: usize, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_seq(self) |
| } |
| |
| fn deserialize_tuple_struct<V: Visitor<'de>>( |
| self, |
| _name: &'static str, |
| _len: usize, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_seq(self) |
| } |
| |
| fn deserialize_map<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| if !self.has_headers() { |
| visitor.visit_seq(self) |
| } else { |
| visitor.visit_map(self) |
| } |
| } |
| |
| fn deserialize_struct<V: Visitor<'de>>( |
| self, |
| _name: &'static str, |
| _fields: &'static [&'static str], |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| if !self.has_headers() { |
| visitor.visit_seq(self) |
| } else { |
| visitor.visit_map(self) |
| } |
| } |
| |
| fn deserialize_identifier<V: Visitor<'de>>( |
| self, |
| _visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| Err(self.error(DEK::Unsupported("deserialize_identifier".into()))) |
| } |
| |
| fn deserialize_enum<V: Visitor<'de>>( |
| self, |
| _name: &'static str, |
| _variants: &'static [&'static str], |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| visitor.visit_enum(self) |
| } |
| |
| fn deserialize_ignored_any<V: Visitor<'de>>( |
| self, |
| visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| // Read and drop the next field. |
| // This code is reached, e.g., when trying to deserialize a header |
| // that doesn't exist in the destination struct. |
| let _ = self.next_field_bytes()?; |
| visitor.visit_unit() |
| } |
| } |
| |
| impl<'a, 'de: 'a, T: DeRecord<'de>> EnumAccess<'de> |
| for &'a mut DeRecordWrap<T> |
| { |
| type Error = DeserializeError; |
| type Variant = Self; |
| |
| fn variant_seed<V: DeserializeSeed<'de>>( |
| self, |
| seed: V, |
| ) -> Result<(V::Value, Self::Variant), Self::Error> { |
| let variant_name = self.next_field()?; |
| seed.deserialize(variant_name.into_deserializer()).map(|v| (v, self)) |
| } |
| } |
| |
| impl<'a, 'de: 'a, T: DeRecord<'de>> VariantAccess<'de> |
| for &'a mut DeRecordWrap<T> |
| { |
| type Error = DeserializeError; |
| |
| fn unit_variant(self) -> Result<(), Self::Error> { |
| Ok(()) |
| } |
| |
| fn newtype_variant_seed<U: DeserializeSeed<'de>>( |
| self, |
| _seed: U, |
| ) -> Result<U::Value, Self::Error> { |
| let unexp = Unexpected::UnitVariant; |
| Err(DeserializeError::invalid_type(unexp, &"newtype variant")) |
| } |
| |
| fn tuple_variant<V: Visitor<'de>>( |
| self, |
| _len: usize, |
| _visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| let unexp = Unexpected::UnitVariant; |
| Err(DeserializeError::invalid_type(unexp, &"tuple variant")) |
| } |
| |
| fn struct_variant<V: Visitor<'de>>( |
| self, |
| _fields: &'static [&'static str], |
| _visitor: V, |
| ) -> Result<V::Value, Self::Error> { |
| let unexp = Unexpected::UnitVariant; |
| Err(DeserializeError::invalid_type(unexp, &"struct variant")) |
| } |
| } |
| |
| impl<'a, 'de: 'a, T: DeRecord<'de>> SeqAccess<'de> |
| for &'a mut DeRecordWrap<T> |
| { |
| type Error = DeserializeError; |
| |
| fn next_element_seed<U: DeserializeSeed<'de>>( |
| &mut self, |
| seed: U, |
| ) -> Result<Option<U::Value>, Self::Error> { |
| if self.peek_field().is_none() { |
| Ok(None) |
| } else { |
| seed.deserialize(&mut **self).map(Some) |
| } |
| } |
| } |
| |
| impl<'a, 'de: 'a, T: DeRecord<'de>> MapAccess<'de> |
| for &'a mut DeRecordWrap<T> |
| { |
| type Error = DeserializeError; |
| |
| fn next_key_seed<K: DeserializeSeed<'de>>( |
| &mut self, |
| seed: K, |
| ) -> Result<Option<K::Value>, Self::Error> { |
| assert!(self.has_headers()); |
| let field = match self.next_header_bytes()? { |
| None => return Ok(None), |
| Some(field) => field, |
| }; |
| 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) |
| } |
| } |
| |
| /// An Serde deserialization error. |
| #[derive(Clone, Debug, Eq, PartialEq)] |
| pub struct DeserializeError { |
| field: Option<u64>, |
| kind: DeserializeErrorKind, |
| } |
| |
| /// The type of a Serde deserialization error. |
| #[derive(Clone, Debug, Eq, PartialEq)] |
| pub enum DeserializeErrorKind { |
| /// A generic Serde deserialization error. |
| Message(String), |
| /// A generic Serde unsupported error. |
| Unsupported(String), |
| /// This error occurs when a Rust type expects to decode another field |
| /// from a row, but no more fields exist. |
| UnexpectedEndOfRow, |
| /// This error occurs when UTF-8 validation on a field fails. UTF-8 |
| /// validation is only performed when the Rust type requires it (e.g., |
| /// a `String` or `&str` type). |
| InvalidUtf8(str::Utf8Error), |
| /// This error occurs when a boolean value fails to parse. |
| ParseBool(str::ParseBoolError), |
| /// This error occurs when an integer value fails to parse. |
| ParseInt(num::ParseIntError), |
| /// This error occurs when a float value fails to parse. |
| ParseFloat(num::ParseFloatError), |
| } |
| |
| impl SerdeError for DeserializeError { |
| fn custom<T: fmt::Display>(msg: T) -> DeserializeError { |
| DeserializeError { field: None, kind: DEK::Message(msg.to_string()) } |
| } |
| } |
| |
| impl StdError for DeserializeError { |
| fn description(&self) -> &str { |
| self.kind.description() |
| } |
| } |
| |
| impl fmt::Display for DeserializeError { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| if let Some(field) = self.field { |
| write!(f, "field {}: {}", field, self.kind) |
| } else { |
| write!(f, "{}", self.kind) |
| } |
| } |
| } |
| |
| impl fmt::Display for DeserializeErrorKind { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| use self::DeserializeErrorKind::*; |
| |
| match *self { |
| Message(ref msg) => write!(f, "{}", msg), |
| Unsupported(ref which) => { |
| write!(f, "unsupported deserializer method: {}", which) |
| } |
| UnexpectedEndOfRow => write!(f, "{}", self.description()), |
| InvalidUtf8(ref err) => err.fmt(f), |
| ParseBool(ref err) => err.fmt(f), |
| ParseInt(ref err) => err.fmt(f), |
| ParseFloat(ref err) => err.fmt(f), |
| } |
| } |
| } |
| |
| impl DeserializeError { |
| /// Return the field index (starting at 0) of this error, if available. |
| pub fn field(&self) -> Option<u64> { |
| self.field |
| } |
| |
| /// Return the underlying error kind. |
| pub fn kind(&self) -> &DeserializeErrorKind { |
| &self.kind |
| } |
| } |
| |
| impl DeserializeErrorKind { |
| #[allow(deprecated)] |
| fn description(&self) -> &str { |
| use self::DeserializeErrorKind::*; |
| |
| match *self { |
| Message(_) => "deserialization error", |
| Unsupported(_) => "unsupported deserializer method", |
| UnexpectedEndOfRow => "expected field, but got end of row", |
| InvalidUtf8(ref err) => err.description(), |
| ParseBool(ref err) => err.description(), |
| ParseInt(ref err) => err.description(), |
| ParseFloat(ref err) => err.description(), |
| } |
| } |
| } |
| |
| serde_if_integer128! { |
| fn try_positive_integer128(s: &str) -> Option<u128> { |
| s.parse().ok() |
| } |
| |
| fn try_negative_integer128(s: &str) -> Option<i128> { |
| s.parse().ok() |
| } |
| } |
| |
| fn try_positive_integer64(s: &str) -> Option<u64> { |
| s.parse().ok() |
| } |
| |
| fn try_negative_integer64(s: &str) -> Option<i64> { |
| s.parse().ok() |
| } |
| |
| fn try_float(s: &str) -> Option<f64> { |
| s.parse().ok() |
| } |
| |
| fn try_positive_integer64_bytes(s: &[u8]) -> Option<u64> { |
| str::from_utf8(s).ok().and_then(|s| s.parse().ok()) |
| } |
| |
| fn try_negative_integer64_bytes(s: &[u8]) -> Option<i64> { |
| str::from_utf8(s).ok().and_then(|s| s.parse().ok()) |
| } |
| |
| serde_if_integer128! { |
| fn try_positive_integer128_bytes(s: &[u8]) -> Option<u128> { |
| str::from_utf8(s).ok().and_then(|s| s.parse().ok()) |
| } |
| |
| fn try_negative_integer128_bytes(s: &[u8]) -> Option<i128> { |
| str::from_utf8(s).ok().and_then(|s| s.parse().ok()) |
| } |
| } |
| |
| fn try_float_bytes(s: &[u8]) -> Option<f64> { |
| str::from_utf8(s).ok().and_then(|s| s.parse().ok()) |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use std::collections::HashMap; |
| |
| use bstr::BString; |
| use serde::{de::DeserializeOwned, serde_if_integer128, Deserialize}; |
| |
| use super::{deserialize_byte_record, deserialize_string_record}; |
| use crate::byte_record::ByteRecord; |
| use crate::error::Error; |
| use crate::string_record::StringRecord; |
| |
| fn de<D: DeserializeOwned>(fields: &[&str]) -> Result<D, Error> { |
| let record = StringRecord::from(fields); |
| deserialize_string_record(&record, None) |
| } |
| |
| fn de_headers<D: DeserializeOwned>( |
| headers: &[&str], |
| fields: &[&str], |
| ) -> Result<D, Error> { |
| let headers = StringRecord::from(headers); |
| let record = StringRecord::from(fields); |
| deserialize_string_record(&record, Some(&headers)) |
| } |
| |
| fn b<'a, T: AsRef<[u8]> + ?Sized>(bytes: &'a T) -> &'a [u8] { |
| bytes.as_ref() |
| } |
| |
| #[test] |
| fn with_header() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: String, |
| } |
| |
| let got: Foo = |
| de_headers(&["x", "y", "z"], &["hi", "42", "1.3"]).unwrap(); |
| assert_eq!(got, Foo { x: "hi".into(), y: 42, z: 1.3 }); |
| } |
| |
| #[test] |
| fn with_header_unknown() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| #[serde(deny_unknown_fields)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: String, |
| } |
| assert!(de_headers::<Foo>( |
| &["a", "x", "y", "z"], |
| &["foo", "hi", "42", "1.3"], |
| ) |
| .is_err()); |
| } |
| |
| #[test] |
| fn with_header_missing() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: String, |
| } |
| assert!(de_headers::<Foo>(&["y", "z"], &["42", "1.3"],).is_err()); |
| } |
| |
| #[test] |
| fn with_header_missing_ok() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: Option<String>, |
| } |
| |
| let got: Foo = de_headers(&["y", "z"], &["42", "1.3"]).unwrap(); |
| assert_eq!(got, Foo { x: None, y: 42, z: 1.3 }); |
| } |
| |
| #[test] |
| fn with_header_no_fields() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: Option<String>, |
| } |
| |
| let got = de_headers::<Foo>(&["y", "z"], &[]); |
| assert!(got.is_err()); |
| } |
| |
| #[test] |
| fn with_header_empty() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: Option<String>, |
| } |
| |
| let got = de_headers::<Foo>(&[], &[]); |
| assert!(got.is_err()); |
| } |
| |
| #[test] |
| fn with_header_empty_ok() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo; |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Bar {}; |
| |
| let got = de_headers::<Foo>(&[], &[]); |
| assert_eq!(got.unwrap(), Foo); |
| |
| let got = de_headers::<Bar>(&[], &[]); |
| assert_eq!(got.unwrap(), Bar {}); |
| |
| let got = de_headers::<()>(&[], &[]); |
| assert_eq!(got.unwrap(), ()); |
| } |
| |
| #[test] |
| fn without_header() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| z: f64, |
| y: i32, |
| x: String, |
| } |
| |
| let got: Foo = de(&["1.3", "42", "hi"]).unwrap(); |
| assert_eq!(got, Foo { x: "hi".into(), y: 42, z: 1.3 }); |
| } |
| |
| #[test] |
| fn no_fields() { |
| assert!(de::<String>(&[]).is_err()); |
| } |
| |
| #[test] |
| fn one_field() { |
| let got: i32 = de(&["42"]).unwrap(); |
| assert_eq!(got, 42); |
| } |
| |
| serde_if_integer128! { |
| #[test] |
| fn one_field_128() { |
| let got: i128 = de(&["2010223372036854775808"]).unwrap(); |
| assert_eq!(got, 2010223372036854775808); |
| } |
| } |
| |
| #[test] |
| fn two_fields() { |
| let got: (i32, bool) = de(&["42", "true"]).unwrap(); |
| assert_eq!(got, (42, true)); |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo(i32, bool); |
| |
| let got: Foo = de(&["42", "true"]).unwrap(); |
| assert_eq!(got, Foo(42, true)); |
| } |
| |
| #[test] |
| fn two_fields_too_many() { |
| let got: (i32, bool) = de(&["42", "true", "z", "z"]).unwrap(); |
| assert_eq!(got, (42, true)); |
| } |
| |
| #[test] |
| fn two_fields_too_few() { |
| assert!(de::<(i32, bool)>(&["42"]).is_err()); |
| } |
| |
| #[test] |
| fn one_char() { |
| let got: char = de(&["a"]).unwrap(); |
| assert_eq!(got, 'a'); |
| } |
| |
| #[test] |
| fn no_chars() { |
| assert!(de::<char>(&[""]).is_err()); |
| } |
| |
| #[test] |
| fn too_many_chars() { |
| assert!(de::<char>(&["ab"]).is_err()); |
| } |
| |
| #[test] |
| fn simple_seq() { |
| let got: Vec<i32> = de(&["1", "5", "10"]).unwrap(); |
| assert_eq!(got, vec![1, 5, 10]); |
| } |
| |
| #[test] |
| fn simple_hex_seq() { |
| let got: Vec<i32> = de(&["0x7F", "0xA9", "0x10"]).unwrap(); |
| assert_eq!(got, vec![0x7F, 0xA9, 0x10]); |
| } |
| |
| #[test] |
| fn mixed_hex_seq() { |
| let got: Vec<i32> = de(&["0x7F", "0xA9", "10"]).unwrap(); |
| assert_eq!(got, vec![0x7F, 0xA9, 10]); |
| } |
| |
| #[test] |
| fn bad_hex_seq() { |
| assert!(de::<Vec<u8>>(&["7F", "0xA9", "10"]).is_err()); |
| } |
| |
| #[test] |
| fn seq_in_struct() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| xs: Vec<i32>, |
| } |
| let got: Foo = de(&["1", "5", "10"]).unwrap(); |
| assert_eq!(got, Foo { xs: vec![1, 5, 10] }); |
| } |
| |
| #[test] |
| fn seq_in_struct_tail() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| label: String, |
| xs: Vec<i32>, |
| } |
| let got: Foo = de(&["foo", "1", "5", "10"]).unwrap(); |
| assert_eq!(got, Foo { label: "foo".into(), xs: vec![1, 5, 10] }); |
| } |
| |
| #[test] |
| fn map_headers() { |
| let got: HashMap<String, i32> = |
| de_headers(&["a", "b", "c"], &["1", "5", "10"]).unwrap(); |
| assert_eq!(got.len(), 3); |
| assert_eq!(got["a"], 1); |
| assert_eq!(got["b"], 5); |
| assert_eq!(got["c"], 10); |
| } |
| |
| #[test] |
| fn map_no_headers() { |
| let got = de::<HashMap<String, i32>>(&["1", "5", "10"]); |
| assert!(got.is_err()); |
| } |
| |
| #[test] |
| fn bytes() { |
| let got: Vec<u8> = de::<BString>(&["foobar"]).unwrap().into(); |
| assert_eq!(got, b"foobar".to_vec()); |
| } |
| |
| #[test] |
| fn adjacent_fixed_arrays() { |
| let got: ([u32; 2], [u32; 2]) = de(&["1", "5", "10", "15"]).unwrap(); |
| assert_eq!(got, ([1, 5], [10, 15])); |
| } |
| |
| #[test] |
| fn enum_label_simple_tagged() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Row { |
| label: Label, |
| x: f64, |
| } |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| #[serde(rename_all = "snake_case")] |
| enum Label { |
| Foo, |
| Bar, |
| Baz, |
| } |
| |
| let got: Row = de_headers(&["label", "x"], &["bar", "5"]).unwrap(); |
| assert_eq!(got, Row { label: Label::Bar, x: 5.0 }); |
| } |
| |
| #[test] |
| fn enum_untagged() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Row { |
| x: Boolish, |
| y: Boolish, |
| z: Boolish, |
| } |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| #[serde(rename_all = "snake_case")] |
| #[serde(untagged)] |
| enum Boolish { |
| Bool(bool), |
| Number(i64), |
| String(String), |
| } |
| |
| let got: Row = |
| de_headers(&["x", "y", "z"], &["true", "null", "1"]).unwrap(); |
| assert_eq!( |
| got, |
| Row { |
| x: Boolish::Bool(true), |
| y: Boolish::String("null".into()), |
| z: Boolish::Number(1), |
| } |
| ); |
| } |
| |
| #[test] |
| fn option_empty_field() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| a: Option<i32>, |
| b: String, |
| c: Option<i32>, |
| } |
| |
| let got: Foo = |
| de_headers(&["a", "b", "c"], &["", "foo", "5"]).unwrap(); |
| assert_eq!(got, Foo { a: None, b: "foo".into(), c: Some(5) }); |
| } |
| |
| #[test] |
| fn option_invalid_field() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo { |
| #[serde(deserialize_with = "crate::invalid_option")] |
| a: Option<i32>, |
| #[serde(deserialize_with = "crate::invalid_option")] |
| b: Option<i32>, |
| #[serde(deserialize_with = "crate::invalid_option")] |
| c: Option<i32>, |
| } |
| |
| let got: Foo = |
| de_headers(&["a", "b", "c"], &["xyz", "", "5"]).unwrap(); |
| assert_eq!(got, Foo { a: None, b: None, c: Some(5) }); |
| } |
| |
| #[test] |
| fn borrowed() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Foo<'a, 'c> { |
| a: &'a str, |
| b: i32, |
| c: &'c str, |
| } |
| |
| let headers = StringRecord::from(vec!["a", "b", "c"]); |
| let record = StringRecord::from(vec!["foo", "5", "bar"]); |
| let got: Foo = |
| deserialize_string_record(&record, Some(&headers)).unwrap(); |
| assert_eq!(got, Foo { a: "foo", b: 5, c: "bar" }); |
| } |
| |
| #[test] |
| fn borrowed_map() { |
| use std::collections::HashMap; |
| |
| let headers = StringRecord::from(vec!["a", "b", "c"]); |
| let record = StringRecord::from(vec!["aardvark", "bee", "cat"]); |
| let got: HashMap<&str, &str> = |
| deserialize_string_record(&record, Some(&headers)).unwrap(); |
| |
| let expected: HashMap<&str, &str> = |
| headers.iter().zip(&record).collect(); |
| assert_eq!(got, expected); |
| } |
| |
| #[test] |
| fn borrowed_map_bytes() { |
| use std::collections::HashMap; |
| |
| let headers = ByteRecord::from(vec![b"a", b"\xFF", b"c"]); |
| let record = ByteRecord::from(vec!["aardvark", "bee", "cat"]); |
| let got: HashMap<&[u8], &[u8]> = |
| deserialize_byte_record(&record, Some(&headers)).unwrap(); |
| |
| let expected: HashMap<&[u8], &[u8]> = |
| headers.iter().zip(&record).collect(); |
| assert_eq!(got, expected); |
| } |
| |
| #[test] |
| fn flatten() { |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Input { |
| x: f64, |
| y: f64, |
| } |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Properties { |
| prop1: f64, |
| prop2: f64, |
| } |
| |
| #[derive(Deserialize, Debug, PartialEq)] |
| struct Row { |
| #[serde(flatten)] |
| input: Input, |
| #[serde(flatten)] |
| properties: Properties, |
| } |
| |
| let header = StringRecord::from(vec!["x", "y", "prop1", "prop2"]); |
| let record = StringRecord::from(vec!["1", "2", "3", "4"]); |
| let got: Row = record.deserialize(Some(&header)).unwrap(); |
| assert_eq!( |
| got, |
| Row { |
| input: Input { x: 1.0, y: 2.0 }, |
| properties: Properties { prop1: 3.0, prop2: 4.0 }, |
| } |
| ); |
| } |
| |
| #[test] |
| fn partially_invalid_utf8() { |
| #[derive(Debug, Deserialize, PartialEq)] |
| struct Row { |
| h1: String, |
| h2: BString, |
| h3: String, |
| } |
| |
| let headers = ByteRecord::from(vec![b"h1", b"h2", b"h3"]); |
| let record = |
| ByteRecord::from(vec![b(b"baz"), b(b"foo\xFFbar"), b(b"quux")]); |
| let got: Row = |
| deserialize_byte_record(&record, Some(&headers)).unwrap(); |
| assert_eq!( |
| got, |
| Row { |
| h1: "baz".to_string(), |
| h2: BString::from(b"foo\xFFbar".to_vec()), |
| h3: "quux".to_string(), |
| } |
| ); |
| } |
| } |