[serde] help on empty json + custom deserializer

Hello people,
i am having problems with serde (deserialization).
here's the playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c684bca43433c2dcabc6c4209f4a6e5f
i did put some comments in line 57

Basically I can't get the two json strings to work (one requires a custom deserializer, and in the other one i don't need the custom deserializer but it appear to be forced).

Can someone enlighten me on what I should do?

Thanks

#[macro_use]
extern crate serde_derive;

use serde_json::Result;

fn main() -> Result<()> {
    /*
    if let Data::Pusher {
        activity_timeout,
        socket_id,
    } = response.data
    {
        println!("{:#?}", activity_timeout);
    };
    */
    
    /*
    println!("{:#?}", response.data);

    let data3 = r#"
    {
        "data": [
                ["109.00000", "0.02563590"],
                ["109.00000", "0.03673540"]
        ],
        "event": "updated"
    }"#;

    let response: Response = serde_json::from_str(data3)?;
    println!("{:#?}", response);

    if let Data::Updated(a) = response.data {
        println!("{:#?}", a.first());
    };
    */

    let data4 = r#"
        {"data":"{\"activity_timeout\":120,\"socket_id\":\"blalba\"}","event":"pusher:connection_established"}
    "#;

    let response: Response = serde_json::from_str(data4)?;
    println!("{:#?}", response);

    let data5 = r#"
        {"channel":"test","event":"test:subscription_succeeded", "data": {}}
    "#;

    let response: Response = serde_json::from_str(data5)?;
    println!("{:#?}", response);

    Ok(())
}

#[derive(Deserialize, Debug)]
pub struct Response {
    event: String,
    // problem: data5 fails even if 'skip_serializing_if = "Map::is_empty"' is set
    // apparently the error comes from json_string
    #[serde(default, skip_serializing_if = "Map::is_empty", with = "json_string")]
    pub data: Option<Data>,
}

use std::collections::HashMap;

#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum Data {
    Pusher {
        activity_timeout: u32,
        socket_id: String,
    },
    Updated(Vec<[String; 2]>),
}

mod json_string {
    use serde::de::{self, Deserialize, DeserializeOwned, Deserializer};
    use serde::ser::{self, Serialize, Serializer};
    use serde_json;

    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer,
    {
        let j = serde_json::to_string(value).map_err(ser::Error::custom)?;
        j.serialize(serializer)
    }

    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
    where
        T: DeserializeOwned,
        D: Deserializer<'de>,
    {
        let j = String::deserialize(deserializer)?;
        serde_json::from_str(&j).map_err(de::Error::custom)
    }
}

(Playground)

Output:

Response {
    event: "pusher:connection_established",
    data: Some(
        Pusher {
            activity_timeout: 120,
            socket_id: "blalba",
        },
    ),
}

Errors:

   Compiling playground v0.0.1 (/playground)
warning: unused import: `std::collections::HashMap`
  --> src/main.rs:61:5
   |
61 | use std::collections::HashMap;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: function is never used: `serialize`
  --> src/main.rs:78:12
   |
78 |     pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
   |            ^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

warning: 2 warnings emitted

    Finished dev [unoptimized + debuginfo] target(s) in 1.05s
     Running `target/debug/playground`
Error: Error("invalid type: map, expected a string", line: 2, column: 73)

Did you mean to write

{"channel":"test","event":"test:subscription_succeeded", "data": "{}"}

(with "" around the data object)?

solved it thanks to the help of a user (Sampersand, saved my day) via another channel (discord).
had to implement an enum inside the deserializer

mod json_string {
    use serde::de::{self, Deserialize, DeserializeOwned, Deserializer};
    use serde::ser::{self, Serialize, Serializer};
    use serde_json;

    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer,
    {
        let j = serde_json::to_string(value).map_err(ser::Error::custom)?;
        j.serialize(serializer)
    }

    #[derive(Deserialize)]
    #[serde(untagged)]
    enum DataOrString<T> {
        Data(T),
        Empty {},
        String(String),
    }

    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
    where
        T: DeserializeOwned,
        D: Deserializer<'de>,
    {
        match DataOrString::deserialize(deserializer)? {
            DataOrString::Data(data) => Ok(data),
            DataOrString::Empty {} => Ok(None),
            DataOrString::String(data_string) => {
                serde_json::from_str(&data_string).map_err(de::Error::custom)
            }
        }
    }
}

No, data came in as described.
Someone recommended the solution posted below.

Thanks for your help!

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.