From 63561609a6517f0a446d304a6d0191adeda54cfa Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 9 Aug 2015 21:42:11 -0700 Subject: [PATCH] Add Error::length_mismatch, Error::type_mismatch, and de::Type This improves error handling to match the needs of msgpack --- serde/src/de/impls.rs | 41 ++++++++++---------- serde/src/de/mod.rs | 83 +++++++++++++++++++++++++++++++++-------- serde/src/de/value.rs | 4 +- serde_json/src/value.rs | 4 +- 4 files changed, 92 insertions(+), 40 deletions(-) diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index 48a194f3..5dd823a2 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -34,6 +34,7 @@ use de::{ Error, MapVisitor, SeqVisitor, + Type, VariantVisitor, Visitor, }; @@ -85,7 +86,7 @@ impl Visitor for BoolVisitor { match s.trim() { "true" => Ok(true), "false" => Ok(false), - _ => Err(Error::syntax("expected `true` or `false`")), + _ => Err(Error::type_mismatch(Type::Bool)), } } } @@ -101,14 +102,14 @@ impl Deserialize for bool { /////////////////////////////////////////////////////////////////////////////// macro_rules! impl_deserialize_num_method { - ($src_ty:ty, $method:ident, $from_method:ident) => { + ($src_ty:ty, $method:ident, $from_method:ident, $ty:expr) => { #[inline] fn $method(&mut self, v: $src_ty) -> Result where E: Error, { match FromPrimitive::$from_method(v) { Some(v) => Ok(v), - None => Err(Error::syntax("expected a number")), + None => Err(Error::type_mismatch($ty)), } } } @@ -132,24 +133,24 @@ impl< > Visitor for PrimitiveVisitor { type Value = T; - impl_deserialize_num_method!(isize, visit_isize, from_isize); - impl_deserialize_num_method!(i8, visit_i8, from_i8); - impl_deserialize_num_method!(i16, visit_i16, from_i16); - impl_deserialize_num_method!(i32, visit_i32, from_i32); - impl_deserialize_num_method!(i64, visit_i64, from_i64); - impl_deserialize_num_method!(usize, visit_usize, from_usize); - impl_deserialize_num_method!(u8, visit_u8, from_u8); - impl_deserialize_num_method!(u16, visit_u16, from_u16); - impl_deserialize_num_method!(u32, visit_u32, from_u32); - impl_deserialize_num_method!(u64, visit_u64, from_u64); - impl_deserialize_num_method!(f32, visit_f32, from_f32); - impl_deserialize_num_method!(f64, visit_f64, from_f64); + impl_deserialize_num_method!(isize, visit_isize, from_isize, Type::Isize); + impl_deserialize_num_method!(i8, visit_i8, from_i8, Type::I8); + impl_deserialize_num_method!(i16, visit_i16, from_i16, Type::I16); + impl_deserialize_num_method!(i32, visit_i32, from_i32, Type::I32); + impl_deserialize_num_method!(i64, visit_i64, from_i64, Type::I64); + impl_deserialize_num_method!(usize, visit_usize, from_usize, Type::Usize); + impl_deserialize_num_method!(u8, visit_u8, from_u8, Type::U8); + impl_deserialize_num_method!(u16, visit_u16, from_u16, Type::U16); + impl_deserialize_num_method!(u32, visit_u32, from_u32, Type::U32); + impl_deserialize_num_method!(u64, visit_u64, from_u64, Type::U64); + impl_deserialize_num_method!(f32, visit_f32, from_f32, Type::F32); + impl_deserialize_num_method!(f64, visit_f64, from_f64, Type::F64); #[inline] fn visit_str(&mut self, v: &str) -> Result where E: Error, { - str::FromStr::from_str(v.trim()).or(Err(Error::syntax("expected a str"))) + str::FromStr::from_str(v.trim()).or(Err(Error::type_mismatch(Type::Str))) } } @@ -200,7 +201,7 @@ impl Visitor for CharVisitor { let mut iter = v.chars(); if let Some(v) = iter.next() { if iter.next().is_some() { - Err(Error::syntax("expected a character")) + Err(Error::type_mismatch(Type::Char)) } else { Ok(v) } @@ -243,7 +244,7 @@ impl Visitor for StringVisitor { { match str::from_utf8(v) { Ok(s) => Ok(s.to_string()), - Err(_) => Err(Error::syntax("expected utf8 `&[u8]`")), + Err(_) => Err(Error::type_mismatch(Type::String)), } } @@ -252,7 +253,7 @@ impl Visitor for StringVisitor { { match String::from_utf8(v) { Ok(s) => Ok(s), - Err(_) => Err(Error::syntax("expected utf8 `&[u8]`")), + Err(_) => Err(Error::type_mismatch(Type::String)), } } } @@ -900,7 +901,7 @@ impl Deserialize for Result where T: Deserialize, E: Deserialize { _ => { match str::from_utf8(value) { Ok(value) => Err(Error::unknown_field(value)), - Err(_) => Err(Error::syntax("expected a `&[u8]`")), + Err(_) => Err(Error::type_mismatch(Type::String)), } } } diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index db83bdc2..9e894d5d 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -5,16 +5,67 @@ pub mod value; /////////////////////////////////////////////////////////////////////////////// -pub trait Error { +/// `Error` is a trait that allows a `Deserialize` to generically create a +/// `Deserializer` error. +pub trait Error: Sized { + /// Raised when there is general error when deserializing a type. fn syntax(msg: &str) -> Self; + /// Raised when a fixed sized sequence or map was passed in the wrong amount of arguments. + fn length_mismatch(_len: usize) -> Self { + Error::syntax("incorrect length") + } + + /// Raised when a `Deserialize` was passed an incorrect type. + fn type_mismatch(_type: Type) -> Self { + Error::syntax("incorrect type") + } + + /// Raised when a `Deserialize` type unexpectedly hit the end of the stream. fn end_of_stream() -> Self; + /// Raised when a `Deserialize` struct type received an unexpected struct field. fn unknown_field(field: &str) -> Self; + /// Raised when a `Deserialize` struct type did not receive a field. fn missing_field(field: &'static str) -> Self; } +/// `Type` represents all the primitive types that can be deserialized. This is used by +/// `Error::kind_mismatch`. +pub enum Type { + Bool, + Usize, + U8, + U16, + U32, + U64, + Isize, + I8, + I16, + I32, + I64, + F32, + F64, + Char, + Str, + String, + Unit, + Option, + Seq, + Map, + UnitStruct, + NewtypeStruct, + TupleStruct, + Struct, + Tuple, + Enum, + StructVariant, + TupleVariant, + UnitVariant, + Bytes, +} + /////////////////////////////////////////////////////////////////////////////// pub trait Deserialize { @@ -304,7 +355,7 @@ pub trait Visitor { fn visit_bool(&mut self, _v: bool) -> Result where E: Error, { - Err(Error::syntax("expected a bool")) + Err(Error::type_mismatch(Type::Bool)) } fn visit_isize(&mut self, v: isize) -> Result @@ -334,7 +385,7 @@ pub trait Visitor { fn visit_i64(&mut self, _v: i64) -> Result where E: Error, { - Err(Error::syntax("expected a i64")) + Err(Error::type_mismatch(Type::I64)) } fn visit_usize(&mut self, v: usize) -> Result @@ -364,7 +415,7 @@ pub trait Visitor { fn visit_u64(&mut self, _v: u64) -> Result where E: Error, { - Err(Error::syntax("expected a u64")) + Err(Error::type_mismatch(Type::U64)) } fn visit_f32(&mut self, v: f32) -> Result @@ -376,7 +427,7 @@ pub trait Visitor { fn visit_f64(&mut self, _v: f64) -> Result where E: Error, { - Err(Error::syntax("expected a f64")) + Err(Error::type_mismatch(Type::F64)) } #[inline] @@ -391,7 +442,7 @@ pub trait Visitor { fn visit_str(&mut self, _v: &str) -> Result where E: Error, { - Err(Error::syntax("expected a str")) + Err(Error::type_mismatch(Type::Str)) } #[inline] @@ -404,7 +455,7 @@ pub trait Visitor { fn visit_unit(&mut self) -> Result where E: Error, { - Err(Error::syntax("expected a unit")) + Err(Error::type_mismatch(Type::Unit)) } #[inline] @@ -417,37 +468,37 @@ pub trait Visitor { fn visit_none(&mut self) -> Result where E: Error, { - Err(Error::syntax("expected an Option::None")) + Err(Error::type_mismatch(Type::Option)) } fn visit_some(&mut self, _deserializer: &mut D) -> Result where D: Deserializer, { - Err(Error::syntax("expected an Option::Some")) + Err(Error::type_mismatch(Type::Option)) } fn visit_newtype_struct(&mut self, _deserializer: &mut D) -> Result where D: Deserializer, { - Err(Error::syntax("expected a newtype struct")) + Err(Error::type_mismatch(Type::NewtypeStruct)) } fn visit_seq(&mut self, _visitor: V) -> Result where V: SeqVisitor, { - Err(Error::syntax("expected a sequence")) + Err(Error::type_mismatch(Type::Seq)) } fn visit_map(&mut self, _visitor: V) -> Result where V: MapVisitor, { - Err(Error::syntax("expected a map")) + Err(Error::type_mismatch(Type::Map)) } fn visit_bytes(&mut self, _v: &[u8]) -> Result where E: Error, { - Err(Error::syntax("expected a &[u8]")) + Err(Error::type_mismatch(Type::Bytes)) } fn visit_byte_buf(&mut self, v: Vec) -> Result @@ -593,7 +644,7 @@ pub trait VariantVisitor { /// `visit_unit` is called when deserializing a variant with no values. fn visit_unit(&mut self) -> Result<(), Self::Error> { - Err(Error::syntax("expected a univ variant")) + Err(Error::type_mismatch(Type::UnitVariant)) } /// `visit_newtype` is called when deserializing a variant with a single value. By default this @@ -612,7 +663,7 @@ pub trait VariantVisitor { _visitor: V) -> Result where V: Visitor { - Err(Error::syntax("expected a tuple variant")) + Err(Error::type_mismatch(Type::TupleVariant)) } /// `visit_struct` is called when deserializing a struct-like variant. @@ -621,7 +672,7 @@ pub trait VariantVisitor { _visitor: V) -> Result where V: Visitor { - Err(Error::syntax("expected a struct variant")) + Err(Error::type_mismatch(Type::StructVariant)) } } diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs index b6c6f0fe..3492a5c1 100644 --- a/serde/src/de/value.rs +++ b/serde/src/de/value.rs @@ -261,7 +261,7 @@ impl de::SeqVisitor for SeqDeserializer if self.len == 0 { Ok(()) } else { - Err(de::Error::end_of_stream()) + Err(de::Error::length_mismatch(self.len)) } } @@ -382,7 +382,7 @@ impl de::MapVisitor for MapDeserializer if self.len == 0 { Ok(()) } else { - Err(de::Error::end_of_stream()) + Err(de::Error::length_mismatch(self.len)) } } diff --git a/serde_json/src/value.rs b/serde_json/src/value.rs index 6ebd5cf8..6ef293ad 100644 --- a/serde_json/src/value.rs +++ b/serde_json/src/value.rs @@ -843,7 +843,7 @@ impl<'a> de::SeqVisitor for SeqDeserializer<'a> { if self.len == 0 { Ok(()) } else { - Err(de::Error::end_of_stream()) + Err(de::Error::length_mismatch(self.len)) } } @@ -888,7 +888,7 @@ impl<'a> de::MapVisitor for MapDeserializer<'a> { if self.len == 0 { Ok(()) } else { - Err(de::Error::end_of_stream()) + Err(de::Error::length_mismatch(self.len)) } }