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

#[serde(flatten)] doesn't work with context! (sometimes) #222

Open
paolobarbolini opened this issue Mar 10, 2023 · 2 comments
Open

#[serde(flatten)] doesn't work with context! (sometimes) #222

paolobarbolini opened this issue Mar 10, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@paolobarbolini
Copy link

Description

minijinja::context! and #[serde(flatten)] sometimes don't work correctly together.

Reproduction steps

  1. Clone this repo: https://github.com/paolobarbolini/minijinja-context-flattening-repro
  2. Run cargo run and observe the output

Additional helpful information:

  • Version of minijinja: 0.30.6 - I tried as low as 0.20.0 but it doesn't work there either
  • Version of rustc: 1.68.0
  • Operating system and version: Linux

What did you expect

I was expecting minijinja::context! to be equal to serde_json::json!

@mitsuhiko
Copy link
Owner

I'm not entirely sure why flatten does not work here but given how big of a hack it is, I'm not terribly surprised. For what it's worth the issue here is unlikely to be context! which is just syntax support for creating a Value holding a map. You can probably repro this also this way:

#[derive(Serialize)]
struct Foo {
    val2: i32,
    #[serde(flatten)]
    flattened: minijinja::Value,
}

@mitsuhiko mitsuhiko added the bug Something isn't working label Mar 10, 2023
@mitsuhiko
Copy link
Owner

So the issue here is more or less the following: a Value when serialized for internal usage turns into a struct (we use in-band signalling here: serde-rs/serde#1463) which is later picked up again. That struct looks something like this:

\x01__minijinja_ValueHandle {
    handle: i64
}

The handle is a reference to an internal counter of the value, which is then picked up from a thread local stashed away slot. When serde(flatten) comes in, it detects that handle and inlines it. This means that this:

#[derive(Serialize)]
struct Foo {
    val2: i32,
    #[serde(flatten)]
    flattened: minijinja::Value,
}

Turns into this:

{
    "val2": 32, // assuming val2: 32
    "handle": 1 // assuming flattened: Value
}

I changed the serialization format to an enum for testing purposes, but then the end result looks like this:

error: can only flatten structs and maps (got an enum)

In some sense it would be necessary to detect that flattening is requested, and to then dump out the structural form of the value rather than the reference. There is currently no way to detect this as serde does not communicate to the serialization interface that flattening is requested. This relates to this issue in some sense: serde-rs/serde#1183

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants