Custom serde deserializer issues with supporting serde(flatten)

I have written a custom deserializer which works for what I need, but I was messing about with adding #[serde(flatten)] to a struct and noticed it no longer worked. I tracked the issue down to serde calling deserialize_any instead of one of the type hinted function e.g. deserialize_i32. Since my format is not self describing I need the type hints from serde to correctly deserialize each field.

Does flatten not support formats that arent self descriptive?

Is there away around this?

Do I need to explictly tell serde that deserialize_any does not work? I was forced to implement the function and currently just return an error. I have also tried returning visitor.visit_none()

thank you in advance!

For example for the following structs my calls look something like

/*
deserialize_map
  next_key_seed
    deserialize_str // "x"
  next_value_seed
    deserialize_i32 // serde "correctly" calls a type hinted function
  next_key_seed
    deserialize_str // "y"
  next_value_seed
    deserialize_any  // <== here is the issue I want deserialize_i32
*/

#[derive(Deserialize)]
struct params {
  x: i32,
  #[serde(flatten)]
  flat: Flatten,
}

#[derive(Deserialize)]
struct Flatten {
  y: i32,
  z: i32,
}
2 Likes

I recently had this problem too. You can either manually implement Deserialize, or do something like following, which I found to be an easier workaround (there could be better solutions I don't know about):

#[derive(Clone, Deserialize, Serialize)]
struct ParamsFlat {
    x: i32,
    y: i32,
    z: i32,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(from = "ParamsFlat", into = "ParamsFlat")]
pub struct Params {
    pub x: i32,
    pub flat: Flatten,
}

impl From<ParamsFlat> for Params {
    fn from(raw: ParamsFlat) -> Self {
        Self {
            x: raw.x,
            flat: Flatten { y: raw.y, z: raw.z },
        }
    }
}

impl From<Params> for ParamsFlat {
    fn from(p: Params) -> Self {
        Self {
            x: p.x,
            y: p.flat.y,
            z: p.flat.z,
        }
    }
}

I think returning an error is the right thing to do for deserialize_any

1 Like