Skip to content

Commit 4a4f0f0

Browse files
authored
Add missing property name to the "property missing" error message (#206)
1 parent d719bd1 commit 4a4f0f0

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

lib/src/types/serde/element.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,23 @@ pub enum ElementDataValue<'de> {
4646

4747
pub struct ElementDataDeserializer<'de, T> {
4848
data: T,
49+
field_name: Option<&'static str>,
4950
_lifetime: PhantomData<&'de ()>,
5051
}
5152

5253
impl<'de, T: ElementData<'de>> ElementDataDeserializer<'de, T> {
5354
pub fn new(data: T) -> Self {
5455
Self {
5556
data,
57+
field_name: None,
58+
_lifetime: PhantomData,
59+
}
60+
}
61+
62+
pub fn with_field_name(data: T, field_name: &'static str) -> Self {
63+
Self {
64+
data,
65+
field_name: Some(field_name),
5666
_lifetime: PhantomData,
5767
}
5868
}
@@ -77,7 +87,7 @@ impl<'de, T: ElementData<'de>> ElementDataDeserializer<'de, T> {
7787
(
7888
BorrowedStr(f),
7989
properties.and_then(|p| p.get(f)).map_or_else(
80-
|| AdditionalData::Element(self.data),
90+
|| AdditionalData::Element(self.data, f),
8191
|v| AdditionalData::Property(v),
8292
),
8393
)
@@ -270,7 +280,7 @@ impl<'de, T: ElementData<'de>> Deserializer<'de> for ElementDataDeserializer<'de
270280
where
271281
V: Visitor<'de>,
272282
{
273-
Err(DeError::PropertyMissingButRequired)
283+
Err(DeError::PropertyMissingButRequired(self.field_name))
274284
}
275285
}
276286

@@ -490,7 +500,7 @@ impl<'de> IntoDeserializer<'de, DeError> for BorrowedStr<'de> {
490500
#[derive(Copy, Clone, Debug)]
491501
enum AdditionalData<'de, T> {
492502
Property(&'de BoltType),
493-
Element(T),
503+
Element(T, &'static str),
494504
}
495505

496506
enum AdditionalDataDeserializer<'de, T> {
@@ -544,9 +554,9 @@ impl<'de, T: ElementData<'de>> IntoDeserializer<'de, DeError> for AdditionalData
544554
AdditionalData::Property(v) => {
545555
AdditionalDataDeserializer::Property(v.into_deserializer())
546556
}
547-
AdditionalData::Element(v) => {
548-
AdditionalDataDeserializer::Element(ElementDataDeserializer::new(v))
549-
}
557+
AdditionalData::Element(v, field_name) => AdditionalDataDeserializer::Element(
558+
ElementDataDeserializer::with_field_name(v, field_name),
559+
),
550560
}
551561
}
552562
}

lib/src/types/serde/error.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,14 @@ pub enum DeError {
5656
NoSuchProperty,
5757

5858
#[error(
59-
"The property is missing but the deserializer still expects a value. \
59+
"{} is missing but the deserializer still expects a value. \
6060
If you have an optional property with a default value, you need to \
6161
use an Option<T> instead (the default attribute does not work in \
6262
this particular instance). If you meant to extract additional data \
63-
other than properties, you need to use the appropriate struct wrapper."
63+
other than properties, you need to use the appropriate struct wrapper.",
64+
property_missing_msg(.0)
6465
)]
65-
PropertyMissingButRequired,
66+
PropertyMissingButRequired(Option<&'static str>),
6667

6768
#[error("{0}")]
6869
Other(String),
@@ -74,6 +75,13 @@ pub enum DeError {
7475
DateTimeOutOfBounds(&'static str),
7576
}
7677

78+
fn property_missing_msg(field_name: &Option<&'static str>) -> String {
79+
match field_name {
80+
Some(field_name) => format!("The property `{}`", field_name),
81+
None => "A property".to_owned(),
82+
}
83+
}
84+
7785
/// `Unexpected` represents an unexpected invocation of any one of the `Visitor`
7886
/// trait methods.
7987
///
@@ -254,3 +262,23 @@ impl Error for DeError {
254262
Self::Other(msg.to_string())
255263
}
256264
}
265+
266+
#[cfg(test)]
267+
mod tests {
268+
use super::*;
269+
270+
#[test]
271+
fn error_message_for_missing_property() {
272+
let message = "The property `frobnicate` is missing";
273+
274+
assert!(DeError::PropertyMissingButRequired(Some("frobnicate"))
275+
.to_string()
276+
.starts_with(message),);
277+
278+
let message = "A property is missing";
279+
280+
assert!(DeError::PropertyMissingButRequired(None)
281+
.to_string()
282+
.starts_with(message));
283+
}
284+
}

lib/src/types/serde/node.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,10 @@ mod tests {
308308

309309
let node = test_node();
310310
let actual = node.to::<Person>().unwrap_err();
311-
assert!(matches!(actual, DeError::PropertyMissingButRequired));
311+
assert!(matches!(
312+
actual,
313+
DeError::PropertyMissingButRequired(Some("favorite_rust_crate"))
314+
));
312315
}
313316

314317
#[test]

0 commit comments

Comments
 (0)