Serde: Is it possible to define type to be used for deserialize with deserialize_with?

I have tried something with the following, notice the line with marked comment

#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct BSCNormalTransactionResponseSuccessVariantResult {
    block_number: String,

    #[serde(deserialize_with = "de_String_to_numeric")]    // <---- attempt to make it generic
    time_stamp: u128,
    
    #[serde(rename = "txreceipt_status")]
    txreceipt_status: String,

    hash: String,
    nonce: String,
}

then implement deserialize function like this one

fn de_String_to_numeric<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>
{
    let buf = String::deserialize(deserializer)?;
    // convert into serde's custom Error type
    buf.parse::<T>().map_err(serde::de::Error::custom)
}

I would like to reduce the boiler-plate deserializing code as some fields might have u8, u64, etc. Is there any way for us to define a type to hint serde via macro attribute, so I don't have to implement specific deserialize function for u8, u64, and on ?

PS: It works just fine if I don't have T in code, and I need to explicitly replace T with specific type to convert to.

Your de_String_to_numeric function looks fine except for the missing bounds on T, but rustc tells you in the error message that you need to add this to the where clause.

    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Display

Your function doesn't need a string, so you could optimize the code a bit. It doesn't look as neat anymore though.

1 Like

I found the solution by looking at serde-aux; an on-top auxiliary attribute helpers for serde.
See these lines.

In short is that I need to explicitly define constraint of type T as well.

So our solution is now

fn de_String_to_numeric<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: std::str::FromStr + serde::Deserialize<'de>,
    <T as std::str::FromStr>::Err: std::fmt::Display // std::str::FromStr has `Err` type, see https://doc.rust-lang.org/std/str/trait.FromStr.html
{
    let buf = String::deserialize(deserializer)?;
    // convert into serde's custom Error type
    buf.parse::<T>().map_err(serde::de::Error::custom)
}

Thank you, also thanks for additional information. Although I found the solution at similar time as your post. But I will mark your as solution as it drives deeper to the cause with added info. Thanks.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.