Skip to content

Commit 93d8f04

Browse files
authored
Various error improvements (#173)
This commit covers RUST-430 / RUST-437 / RUST-443 / RUST-444 / RUST-312.
1 parent 419d79f commit 93d8f04

File tree

9 files changed

+231
-201
lines changed

9 files changed

+231
-201
lines changed

serde-tests/test.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,21 @@ fn unused_fields7() {
585585
assert_eq!(v, t!(Deserialize::deserialize(d)));
586586
}
587587

588+
#[test]
589+
fn unused_fields_deny() {
590+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
591+
#[serde(deny_unknown_fields)]
592+
struct Foo {
593+
a: i32,
594+
}
595+
596+
let d = Decoder::new(bdoc! {
597+
"a" => 1,
598+
"b" => 2
599+
});
600+
Foo::deserialize(d).expect_err("extra fields should cause failure");
601+
}
602+
588603
#[test]
589604
fn empty_arrays() {
590605
#[derive(Serialize, Deserialize, PartialEq, Debug)]

src/decoder/error.rs

Lines changed: 87 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,60 @@
11
use std::{error, fmt, fmt::Display, io, string};
22

3-
use serde::de::{self, Expected, Unexpected};
3+
use crate::Bson;
4+
use de::Unexpected;
5+
use serde::de;
46

57
/// Possible errors that can arise during decoding.
68
#[derive(Debug)]
79
#[non_exhaustive]
810
pub enum DecoderError {
11+
/// A [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) encountered while deserializing.
912
IoError(io::Error),
13+
14+
/// A [`std::string::FromUtf8Error`](https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html) encountered
15+
/// while decoding a UTF-8 String from the input data.
1016
FromUtf8Error(string::FromUtf8Error),
11-
UnrecognizedDocumentElementType { key: String, element_type: u8 },
12-
InvalidArrayKey(usize, String),
13-
// A field was expected, but none was found.
14-
ExpectedField(&'static str),
15-
// An unexpected field was found.
16-
UnknownField(String),
17-
// There was an error with the syntactical structure of the BSON.
18-
SyntaxError(String),
19-
// The end of the BSON input was reached too soon.
17+
18+
/// While decoding a `Document` from bytes, an unexpected or unsupported element type was
19+
/// encountered.
20+
UnrecognizedDocumentElementType {
21+
/// The key at which an unexpected/unsupported element type was encountered.
22+
key: String,
23+
24+
/// The encountered element type.
25+
element_type: u8,
26+
},
27+
28+
/// There was an error with the syntactical structure of the BSON.
29+
SyntaxError { message: String },
30+
31+
/// The end of the BSON input was reached too soon.
2032
EndOfStream,
21-
// Invalid Type
22-
InvalidType(String),
23-
// Invalid Length
24-
InvalidLength(usize, String),
25-
// Duplicated Field
26-
DuplicatedField(&'static str),
27-
// Unknown Variant
28-
UnknownVariant(String),
29-
// Invalid value
30-
InvalidValue(String),
31-
// Invalid timestamp
33+
34+
/// An invalid timestamp was encountered while decoding.
3235
InvalidTimestamp(i64),
33-
// Ambiguous timestamp
36+
37+
/// An ambiguous timestamp was encountered while decoding.
3438
AmbiguousTimestamp(i64),
3539

36-
Unknown(String),
40+
/// Returned when an index into an array was expected, but got a something else instead.
41+
/// BSON arrays are expected to be stored as subdocuments with numbered keys. If the input data
42+
/// contains one which is stored with a different format for its keys, this error will be
43+
/// returned.
44+
InvalidArrayKey {
45+
/// The key that was encountered in the input data.
46+
actual_key: String,
47+
48+
/// The index the key was expected to correspond to.
49+
expected_key: usize,
50+
},
51+
52+
/// A general error encountered during deserialization.
53+
/// See: https://docs.serde.rs/serde/de/trait.Error.html
54+
DeserializationError {
55+
/// A message describing the error.
56+
message: String,
57+
},
3758
}
3859

3960
impl From<io::Error> for DecoderError {
@@ -61,58 +82,24 @@ impl fmt::Display for DecoderError {
6182
"unrecognized element type for key \"{}\": `{}`",
6283
key, element_type
6384
),
64-
DecoderError::InvalidArrayKey(ref want, ref got) => {
65-
write!(fmt, "invalid array key: expected `{}`, got `{}`", want, got)
66-
}
67-
DecoderError::ExpectedField(field_type) => {
68-
write!(fmt, "expected a field of type `{}`", field_type)
69-
}
70-
DecoderError::UnknownField(ref field) => write!(fmt, "unknown field `{}`", field),
71-
DecoderError::SyntaxError(ref inner) => inner.fmt(fmt),
85+
DecoderError::InvalidArrayKey {
86+
ref actual_key,
87+
ref expected_key,
88+
} => write!(
89+
fmt,
90+
"invalid array key: expected `{}`, got `{}`",
91+
expected_key, actual_key
92+
),
93+
DecoderError::SyntaxError { ref message } => message.fmt(fmt),
7294
DecoderError::EndOfStream => fmt.write_str("end of stream"),
73-
DecoderError::InvalidType(ref desc) => desc.fmt(fmt),
74-
DecoderError::InvalidLength(ref len, ref desc) => {
75-
write!(fmt, "expecting length {}, {}", len, desc)
76-
}
77-
DecoderError::DuplicatedField(ref field) => write!(fmt, "duplicated field `{}`", field),
78-
DecoderError::UnknownVariant(ref var) => write!(fmt, "unknown variant `{}`", var),
79-
DecoderError::InvalidValue(ref desc) => desc.fmt(fmt),
80-
DecoderError::Unknown(ref inner) => inner.fmt(fmt),
95+
DecoderError::DeserializationError { ref message } => message.fmt(fmt),
8196
DecoderError::InvalidTimestamp(ref i) => write!(fmt, "no such local time {}", i),
8297
DecoderError::AmbiguousTimestamp(ref i) => write!(fmt, "ambiguous local time {}", i),
8398
}
8499
}
85100
}
86101

87102
impl error::Error for DecoderError {
88-
fn description(&self) -> &str {
89-
match *self {
90-
DecoderError::IoError(ref inner) =>
91-
{
92-
#[allow(deprecated)]
93-
inner.description()
94-
}
95-
DecoderError::FromUtf8Error(ref inner) =>
96-
{
97-
#[allow(deprecated)]
98-
inner.description()
99-
}
100-
DecoderError::UnrecognizedDocumentElementType { .. } => "unrecognized element type",
101-
DecoderError::InvalidArrayKey(..) => "invalid array key",
102-
DecoderError::ExpectedField(_) => "expected a field",
103-
DecoderError::UnknownField(_) => "found an unknown field",
104-
DecoderError::SyntaxError(ref inner) => inner,
105-
DecoderError::EndOfStream => "end of stream",
106-
DecoderError::InvalidType(ref desc) => desc,
107-
DecoderError::InvalidLength(_, ref desc) => desc,
108-
DecoderError::DuplicatedField(_) => "duplicated field",
109-
DecoderError::UnknownVariant(_) => "unknown variant",
110-
DecoderError::InvalidValue(ref desc) => desc,
111-
DecoderError::Unknown(ref inner) => inner,
112-
DecoderError::InvalidTimestamp(..) => "no such local time",
113-
DecoderError::AmbiguousTimestamp(..) => "ambiguous local time",
114-
}
115-
}
116103
fn cause(&self) -> Option<&dyn error::Error> {
117104
match *self {
118105
DecoderError::IoError(ref inner) => Some(inner),
@@ -124,37 +111,41 @@ impl error::Error for DecoderError {
124111

125112
impl de::Error for DecoderError {
126113
fn custom<T: Display>(msg: T) -> DecoderError {
127-
DecoderError::Unknown(msg.to_string())
128-
}
129-
130-
fn invalid_type(_unexp: Unexpected, exp: &dyn Expected) -> DecoderError {
131-
DecoderError::InvalidType(exp.to_string())
132-
}
133-
134-
fn invalid_value(_unexp: Unexpected, exp: &dyn Expected) -> DecoderError {
135-
DecoderError::InvalidValue(exp.to_string())
136-
}
137-
138-
fn invalid_length(len: usize, exp: &dyn Expected) -> DecoderError {
139-
DecoderError::InvalidLength(len, exp.to_string())
140-
}
141-
142-
fn unknown_variant(variant: &str, _expected: &'static [&'static str]) -> DecoderError {
143-
DecoderError::UnknownVariant(variant.to_string())
144-
}
145-
146-
fn unknown_field(field: &str, _expected: &'static [&'static str]) -> DecoderError {
147-
DecoderError::UnknownField(String::from(field))
148-
}
149-
150-
fn missing_field(field: &'static str) -> DecoderError {
151-
DecoderError::ExpectedField(field)
152-
}
153-
154-
fn duplicate_field(field: &'static str) -> DecoderError {
155-
DecoderError::DuplicatedField(field)
114+
DecoderError::DeserializationError {
115+
message: msg.to_string(),
116+
}
156117
}
157118
}
158119

159120
/// Alias for `Result<T, DecoderError>`.
160121
pub type DecoderResult<T> = Result<T, DecoderError>;
122+
123+
impl Bson {
124+
/// Method for converting a given `Bson` value to a `serde::de::Unexpected` for error reporting.
125+
pub(crate) fn as_unexpected(&self) -> Unexpected {
126+
match self {
127+
Bson::Array(_) => Unexpected::Seq,
128+
Bson::Binary(b) => Unexpected::Bytes(b.bytes.as_slice()),
129+
Bson::Boolean(b) => Unexpected::Bool(*b),
130+
Bson::DbPointer(_) => Unexpected::Other("dbpointer"),
131+
Bson::Document(_) => Unexpected::Map,
132+
Bson::FloatingPoint(f) => Unexpected::Float(*f),
133+
Bson::I32(i) => Unexpected::Signed(*i as i64),
134+
Bson::I64(i) => Unexpected::Signed(*i),
135+
Bson::JavaScriptCode(_) => Unexpected::Other("javascript code"),
136+
Bson::JavaScriptCodeWithScope(_) => Unexpected::Other("javascript code with scope"),
137+
Bson::MaxKey => Unexpected::Other("maxkey"),
138+
Bson::MinKey => Unexpected::Other("minkey"),
139+
Bson::Null => Unexpected::Unit,
140+
Bson::Undefined => Unexpected::Other("undefined"),
141+
Bson::ObjectId(_) => Unexpected::Other("objectid"),
142+
Bson::Regex(_) => Unexpected::Other("regex"),
143+
Bson::String(s) => Unexpected::Str(s.as_str()),
144+
Bson::Symbol(_) => Unexpected::Other("symbol"),
145+
Bson::TimeStamp(_) => Unexpected::Other("timestamp"),
146+
Bson::UtcDatetime(_) => Unexpected::Other("datetime"),
147+
#[cfg(feature = "decimal128")]
148+
Bson::Decimal128(_) => Unexpected::Other("decimal128"),
149+
}
150+
}
151+
}

src/decoder/mod.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::{
4545
spec::{self, BinarySubtype},
4646
};
4747

48-
use ::serde::de::Deserialize;
48+
use ::serde::de::{Deserialize, Error};
4949

5050
const MAX_BSON_SIZE: i32 = 16 * 1024 * 1024;
5151

@@ -54,9 +54,9 @@ fn read_string<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderRes
5454

5555
// UTF-8 String must have at least 1 byte (the last 0x00).
5656
if len < 1 {
57-
return Err(DecoderError::InvalidLength(
57+
return Err(DecoderError::invalid_length(
5858
len as usize,
59-
format!("invalid length {} for UTF-8 string", len),
59+
&"UTF-8 string must have at least 1 byte",
6060
));
6161
}
6262

@@ -144,10 +144,18 @@ fn decode_array<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderRe
144144

145145
let (key, val) = decode_bson_kvp(reader, tag, utf8_lossy)?;
146146
match key.parse::<usize>() {
147-
Err(..) => return Err(DecoderError::InvalidArrayKey(arr.len(), key)),
147+
Err(..) => {
148+
return Err(DecoderError::InvalidArrayKey {
149+
actual_key: key,
150+
expected_key: arr.len(),
151+
})
152+
}
148153
Ok(idx) => {
149154
if idx != arr.len() {
150-
return Err(DecoderError::InvalidArrayKey(arr.len(), key));
155+
return Err(DecoderError::InvalidArrayKey {
156+
actual_key: key,
157+
expected_key: arr.len(),
158+
});
151159
}
152160
}
153161
}
@@ -173,9 +181,9 @@ fn decode_bson_kvp<R: Read + ?Sized>(
173181
Some(ElementType::Binary) => {
174182
let len = read_i32(reader)?;
175183
if len < 0 || len > MAX_BSON_SIZE {
176-
return Err(DecoderError::InvalidLength(
184+
return Err(DecoderError::invalid_length(
177185
len as usize,
178-
format!("Invalid binary length of {}", len),
186+
&format!("binary length must be between 0 and {}", MAX_BSON_SIZE).as_str(),
179187
));
180188
}
181189
let subtype = BinarySubtype::from(reader.read_u8()?);

0 commit comments

Comments
 (0)