serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
8.82k stars 748 forks source link

Include Struct Name in Error Message? #2711

Open MyGodItsFull0fStars opened 3 months ago

MyGodItsFull0fStars commented 3 months ago

I use the derive[] variant of Serde to deserialize large files containing various data structures with identical value names. In this issue, I focus on the value name hidden (I included two of the structs I use in this issue).

In at least one of the data types, the hidden value does not always seem available. Hence, I must use an Optional on that specific hidden value. As I want this to be as strict as possible, I don't want to change all values to an Optional<bool> value, but only if necessary.

Now, if I try to call the from_str function, I encounter the error message:

..called `Result::unwrap()` on an `Err` value: Custom("missing field `@hidden`")
    #[derive(Debug, Deserialize, PartialEq, Eq)]
    pub struct CategoryEntry {
        #[serde(rename = "@name")]
        pub name: String,
        #[serde(rename = "@hidden")]
        pub hidden: bool,                      <-------- could fail here
        #[serde(rename = "@id")]
        pub id: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Eq)]
    pub struct InfoLink {
        #[serde(rename = "@name")]
        pub name: String,
        #[serde(rename = "@hidden")]
         pub hidden: bool,                      <-------- or here?
    }

As multiple struct data types are used in the files' deserialization, I cannot pinpoint which of them the error is occurring. Is there a way to add a value similar to tags to additionally add to error messages?

For example, if the mentioned error is encountered for deserializing into a CategoryEntry struct, the message could (if possible) look like this:

..called `Result::unwrap()` on an `Err` value: CategoryEntry("missing field `@hidden`")
1makarov commented 1 month ago

+, I would like to have a structure name or at least a custom description like in the expecting tag for untagget enum.

I have to make a separate field in enum for each deserialisation to know which structure failed.

It would be much more convenient to have one ParseJson error with the structure name than several, most of the time nobody handles the json parsing error additionally, it is used to inform.

MyGodItsFull0fStars commented 1 month ago

@1makarov Thanks for the idea of the separate field in the enum; this might help in some cases.

Yet the above error happens in an Enum that contains both those structures, so I can't quickly pinpoint where the error occurs. So, as you said, having the structure name where the error happens will greatly help.

1makarov commented 1 month ago

@MyGodItsFull0fStars You can also use a wrapper like this (If no specific machining is required):

use std::any::type_name;
use bytes::Bytes;

#[derive(Debug, thiserror::Error)]
#[error("Failed to parse {struct_name} from JSON: {source}")]
pub struct ParseJsonError {
    source: serde_json::Error,
    struct_name: String,
}

pub fn parse_json<T>(json: &Bytes) -> Result<T, ParseJsonError>
where
    T: serde::de::DeserializeOwned,
{
    serde_json::from_slice(json).map_err(|source| ParseJsonError {
        source,
        struct_name: type_name::<T>().to_string(),
    })
}
MyGodItsFull0fStars commented 1 month ago

@1makarov Thank you so, so much! This is super helpful for my problem!