From 8fc8a6a5ca872022b9412003a7ce90f0dce76f9c Mon Sep 17 00:00:00 2001 From: Azriel Hoh Date: Sat, 20 Oct 2018 16:24:16 +1300 Subject: Better error handling when parsing tuples. Issue #225 --- src/de.rs | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) (limited to 'src/de.rs') diff --git a/src/de.rs b/src/de.rs index 4f5a5f2..810b85b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -162,9 +162,19 @@ enum ErrorKind { /// A struct was expected but something else was found ExpectedString, - /// A tuple with a certain number of elements was expected but something else was found + /// A tuple with a certain number of elements was expected but something + /// else was found. ExpectedTuple(usize), + /// Expected table keys to be in increasing tuple index order, but something + /// else was found. + ExpectedTupleIndex { + /// Expected index. + expected: usize, + /// Key that was specified. + found: String, + }, + /// An empty table was expected but entries were found ExpectedEmptyTable, @@ -812,16 +822,24 @@ impl<'de> de::VariantAccess<'de> for InlineTableDeserializer<'de> { let tuple_values = values .into_iter() .enumerate() - .filter_map(|(index, (key, value))| { - // TODO: Is this expensive? - if key == format!("{}", index) { - Some(value) - } else { - // TODO: Err() - unimplemented!() - } + .map(|(index, (key, value))| match key.parse::() { + Ok(key_index) if key_index == index => Ok(value), + Ok(_) | Err(_) => Err(Error::from_kind(ErrorKind::ExpectedTupleIndex { + expected: index, + found: key.to_string(), + })), }) - .collect::>(); // TODO: is this expensive? + // Fold all values into a `Vec`, or return the first error. + .fold(Ok(Vec::with_capacity(len)), |result, value_result| { + result.and_then(|mut tuple_values| match value_result { + Ok(value) => { + tuple_values.push(value); + Ok(tuple_values) + } + // `Result` to `Result, Self::Error>` + Err(e) => Err(e), + }) + })?; if tuple_values.len() == len { de::Deserializer::deserialize_seq( @@ -1521,7 +1539,11 @@ impl fmt::Display for Error { ErrorKind::MultilineStringKey => "multiline strings are not allowed for key".fmt(f)?, ErrorKind::Custom => self.inner.message.fmt(f)?, ErrorKind::ExpectedString => "expected string".fmt(f)?, - ErrorKind::ExpectedTuple(l) => write!(f, "expected tuple with length {}", l)?, + ErrorKind::ExpectedTuple(l) => write!(f, "expected table with length {}", l)?, + ErrorKind::ExpectedTupleIndex { + expected, + ref found, + } => write!(f, "expected table key `{}`, but was `{}`", expected, found)?, ErrorKind::ExpectedEmptyTable => "expected empty table".fmt(f)?, ErrorKind::DottedKeyInvalidType => { "dotted key attempted to extend non-table type".fmt(f)? @@ -1570,7 +1592,8 @@ impl error::Error for Error { ErrorKind::MultilineStringKey => "invalid multiline string for key", ErrorKind::Custom => "a custom error", ErrorKind::ExpectedString => "expected string", - ErrorKind::ExpectedTuple(_) => "expected tuple", + ErrorKind::ExpectedTuple(_) => "expected table length", + ErrorKind::ExpectedTupleIndex { .. } => "expected table key", ErrorKind::ExpectedEmptyTable => "expected empty table", ErrorKind::DottedKeyInvalidType => "dotted key invalid type", ErrorKind::__Nonexhaustive => panic!(), -- cgit v1.2.3