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.