use std::{error::Error as StdError, fmt, iter, num, str}; use serde::{ de::value::BorrowedBytesDeserializer, de::{ Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as SerdeError, IntoDeserializer, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }, serde_if_integer128, }; use crate::{ byte_record::{ByteRecord, ByteRecordIter}, error::{Error, ErrorKind}, 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 { 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, }) }) } pub fn deserialize_byte_record<'de, D: Deserialize<'de>>( record: &'de ByteRecord, headers: Option<&'de ByteRecord>, ) -> Result { 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, }) }) } /// 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` and `DeRecordWrap`. /// Finally, we impl `serde::Deserialize` for `DeRecordWrap` 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, DeserializeError>; /// Extracts the next raw byte header value from the underlying record. fn next_header_bytes( &mut self, ) -> Result, 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; } struct DeRecordWrap(T); impl<'r, T: DeRecord<'r>> DeRecord<'r> for DeRecordWrap { #[inline] fn has_headers(&self) -> bool { self.0.has_headers() } #[inline] fn next_header(&mut self) -> Result, DeserializeError> { self.0.next_header() } #[inline] fn next_header_bytes( &mut self, ) -> Result, 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 { self.0.infer_deserialize(visitor) } } struct DeStringRecord<'r> { it: iter::Peekable>, headers: Option>, 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, DeserializeError> { Ok(self.headers.as_mut().and_then(|it| it.next())) } #[inline] fn next_header_bytes( &mut self, ) -> Result, 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 } } fn infer_deserialize<'de, V: Visitor<'de>>( &mut self, visitor: V, ) -> Result { 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>, headers: Option>, 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, 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, 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 } } fn infer_deserialize<'de, V: Visitor<'de>>( &mut self, visitor: V, ) -> Result { 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>( self, visitor: V, ) -> Result { 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 { type Error = DeserializeError; fn deserialize_any>( self, visitor: V, ) -> Result { self.infer_deserialize(visitor) } fn deserialize_bool>( self, visitor: V, ) -> Result { 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>( self, visitor: V, ) -> Result { visitor.visit_f32( self.next_field()? .parse() .map_err(|err| self.error(DEK::ParseFloat(err)))?, ) } fn deserialize_f64>( self, visitor: V, ) -> Result { visitor.visit_f64( self.next_field()? .parse() .map_err(|err| self.error(DEK::ParseFloat(err)))?, ) } fn deserialize_char>( self, visitor: V, ) -> Result { 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>( self, visitor: V, ) -> Result { self.next_field().and_then(|f| visitor.visit_borrowed_str(f)) } fn deserialize_string>( self, visitor: V, ) -> Result { self.next_field().and_then(|f| visitor.visit_str(f.into())) } fn deserialize_bytes>( self, visitor: V, ) -> Result { self.next_field_bytes().and_then(|f| visitor.visit_borrowed_bytes(f)) } fn deserialize_byte_buf>( self, visitor: V, ) -> Result { self.next_field_bytes() .and_then(|f| visitor.visit_byte_buf(f.to_vec())) } fn deserialize_option>( self, visitor: V, ) -> Result { 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>( self, visitor: V, ) -> Result { visitor.visit_unit() } fn deserialize_unit_struct>( self, _name: &'static str, visitor: V, ) -> Result { visitor.visit_unit() } fn deserialize_newtype_struct>( self, _name: &'static str, visitor: V, ) -> Result { visitor.visit_newtype_struct(self) } fn deserialize_seq>( self, visitor: V, ) -> Result { visitor.visit_seq(self) } fn deserialize_tuple>( self, _len: usize, visitor: V, ) -> Result { visitor.visit_seq(self) } fn deserialize_tuple_struct>( self, _name: &'static str, _len: usize, visitor: V, ) -> Result { visitor.visit_seq(self) } fn deserialize_map>( self, visitor: V, ) -> Result { if !self.has_headers() { visitor.visit_seq(self) } else { visitor.visit_map(self) } } fn deserialize_struct>( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result { if !self.has_headers() { visitor.visit_seq(self) } else { visitor.visit_map(self) } } fn deserialize_identifier>( self, _visitor: V, ) -> Result { Err(self.error(DEK::Unsupported("deserialize_identifier".into()))) } fn deserialize_enum>( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result { visitor.visit_enum(self) } fn deserialize_ignored_any>( self, visitor: V, ) -> Result { // 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 { type Error = DeserializeError; type Variant = Self; fn variant_seed>( 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 { type Error = DeserializeError; fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } fn newtype_variant_seed>( self, _seed: U, ) -> Result { let unexp = Unexpected::UnitVariant; Err(DeserializeError::invalid_type(unexp, &"newtype variant")) } fn tuple_variant>( self, _len: usize, _visitor: V, ) -> Result { let unexp = Unexpected::UnitVariant; Err(DeserializeError::invalid_type(unexp, &"tuple variant")) } fn struct_variant>( self, _fields: &'static [&'static str], _visitor: V, ) -> Result { let unexp = Unexpected::UnitVariant; Err(DeserializeError::invalid_type(unexp, &"struct variant")) } } impl<'a, 'de: 'a, T: DeRecord<'de>> SeqAccess<'de> for &'a mut DeRecordWrap { type Error = DeserializeError; fn next_element_seed>( &mut self, seed: U, ) -> Result, 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 { type Error = DeserializeError; fn next_key_seed>( &mut self, seed: K, ) -> Result, 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>( &mut self, seed: K, ) -> Result { seed.deserialize(&mut **self) } } /// An Serde deserialization error. #[derive(Clone, Debug, Eq, PartialEq)] pub struct DeserializeError { field: Option, 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(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 { 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 { s.parse().ok() } fn try_negative_integer128(s: &str) -> Option { s.parse().ok() } } fn try_positive_integer64(s: &str) -> Option { s.parse().ok() } fn try_negative_integer64(s: &str) -> Option { s.parse().ok() } fn try_float(s: &str) -> Option { s.parse().ok() } fn try_positive_integer64_bytes(s: &[u8]) -> Option { str::from_utf8(s).ok().and_then(|s| s.parse().ok()) } fn try_negative_integer64_bytes(s: &[u8]) -> Option { str::from_utf8(s).ok().and_then(|s| s.parse().ok()) } serde_if_integer128! { fn try_positive_integer128_bytes(s: &[u8]) -> Option { str::from_utf8(s).ok().and_then(|s| s.parse().ok()) } fn try_negative_integer128_bytes(s: &[u8]) -> Option { str::from_utf8(s).ok().and_then(|s| s.parse().ok()) } } fn try_float_bytes(s: &[u8]) -> Option { str::from_utf8(s).ok().and_then(|s| s.parse().ok()) } #[cfg(test)] mod tests { use std::collections::HashMap; use { bstr::BString, serde::{de::DeserializeOwned, serde_if_integer128, Deserialize}, }; use crate::{ byte_record::ByteRecord, error::Error, string_record::StringRecord, }; use super::{deserialize_byte_record, deserialize_string_record}; fn de(fields: &[&str]) -> Result { let record = StringRecord::from(fields); deserialize_string_record(&record, None) } fn de_headers( headers: &[&str], fields: &[&str], ) -> Result { 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::( &["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::(&["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, } 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, } let got = de_headers::(&["y", "z"], &[]); assert!(got.is_err()); } #[test] fn with_header_empty() { #[derive(Deserialize, Debug, PartialEq)] struct Foo { z: f64, y: i32, x: Option, } let got = de_headers::(&[], &[]); 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::(&[], &[]); assert_eq!(got.unwrap(), Foo); let got = de_headers::(&[], &[]); 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::(&[]).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::(&[""]).is_err()); } #[test] fn too_many_chars() { assert!(de::(&["ab"]).is_err()); } #[test] fn simple_seq() { let got: Vec = de(&["1", "5", "10"]).unwrap(); assert_eq!(got, vec![1, 5, 10]); } #[test] fn simple_hex_seq() { let got: Vec = de(&["0x7F", "0xA9", "0x10"]).unwrap(); assert_eq!(got, vec![0x7F, 0xA9, 0x10]); } #[test] fn mixed_hex_seq() { let got: Vec = de(&["0x7F", "0xA9", "10"]).unwrap(); assert_eq!(got, vec![0x7F, 0xA9, 10]); } #[test] fn bad_hex_seq() { assert!(de::>(&["7F", "0xA9", "10"]).is_err()); } #[test] fn seq_in_struct() { #[derive(Deserialize, Debug, PartialEq)] struct Foo { xs: Vec, } 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, } 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 = 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::>(&["1", "5", "10"]); assert!(got.is_err()); } #[test] fn bytes() { let got: Vec = de::(&["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, b: String, c: Option, } 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, #[serde(deserialize_with = "crate::invalid_option")] b: Option, #[serde(deserialize_with = "crate::invalid_option")] c: Option, } 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(), } ); } }