Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

human_readable flag does not get carried through #2704

Open
stroberrysugar opened this issue Feb 24, 2024 · 2 comments
Open

human_readable flag does not get carried through #2704

stroberrysugar opened this issue Feb 24, 2024 · 2 comments

Comments

@stroberrysugar
Copy link

The issue I have is related to serializing chrono's DateTime objects differently based on the human_readable flag. If human_readable is set to true, I need it to be serialized as an ISO string. If it's false, it needs to be serialized as a Bson DateTime object.

However, serde seems to be ignoring the human_readable flag in my code (or the flag isn't being passed through).

I eventually narrowed down the issue to this (in a different project for an minimal, reproducible example).

To do my experiment, I have a struct that serializes to this:

{
  "field1": 0,
  "field2": 0,
  "human_readable": true
}

This JSON output will let me know what the value of the human_readable flag is.

Here's the Rust code that does this:

use bson::SerializerOptions;
use serde::{ser::SerializeStruct, Serialize};

#[derive(Default, Serialize)]
struct Main {
    field1: usize,
    field2: usize,
    #[serde(flatten)]
    serializer_info: SerializerInfo,
}

#[derive(Default)]
struct SerializerInfo;

impl Serialize for SerializerInfo {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let human_readable = serializer.is_human_readable();

        let mut serializer_info = serializer.serialize_struct("SerializerInfo", 1)?;

        serializer_info.serialize_field("human_readable", &human_readable)?;

        serializer_info.end()
    }
}

fn main() {
    let document = bson::to_document_with_options(
        &Main::default(),
        SerializerOptions::builder().human_readable(false).build(),
    )
    .unwrap();

    println!("{}", serde_json::to_string_pretty(&document).unwrap());
}

This code always responds with a JSON output that has human_readable set to true, despite me setting it to false in my bson serializer.

What's interesting is that this problem disappears when I remove the #[serde(flatten)] attribute. This is what I get when I do that:

{
  "field1": 0,
  "field2": 0,
  "serializer_info": {
    "human_readable": false
  }
}

Do you think this is a problem with bson or serde?

@Mingun
Copy link
Contributor

Mingun commented Feb 24, 2024

This is problem with is_human_readable() flag which is not preserved in internal deserializers. I tried to fix that in #1919, but the PR was closed as won't fix.

@survived
Copy link

survived commented Mar 21, 2024

I reproduced the same problem while using ciborium (which is always supposed to be human_readable = false) and #[serde(flatten)]. Things inside of #[serde(flatten)] have human_readable = true. I followed the code in cargo expand, and the issue basically comes down to calling FlatMapSerializer/FlatMapDeserializer which don't implement fn is_human_readable() and it defaults to true.

I think both this structs could accept is_human_readable flag as input and address this issue. #1919 should have done the trick, it's very strange to see it being rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants