SIGN IN SIGN UP
bevyengine / bevy UNCLAIMED

A refreshingly simple data-driven game engine built in Rust

0 0 59 Rust

add #[serde(default)] to Node (and, perhaps other similar structs) (#18883)

# Objective

Many structs that implement `Serialize` and `Deserialize` (when Bevy's
`serialize` feature is enabled) also implement `Default`, but _do not_
apply the `#[serde(default)]` attribute. This requires those who want to
deserialize said structs to explicitly specify **all** struct fields in
their data-interchange format, even if they all end up being their
default values.

For example, I am trying to implement a plugin that allows me to specify
a UI tree in JSON files. I noticed that when I tried to deserialize the
`Node` component (which has **39** fields!) with `serde`, I was met with
an error that in essence would have required me to specify all fields of
`Node` in the JSON file, of which I was only using non-default values
for:
- `height`
- `width`
- `border`
- `flex_direction`

## Solution

1. Apply #[serde(default)] to the `Node` struct
2. If '1' is reasonable, perhaps start a conversation about applying
this attribute to all structs that implement `Serialize`, `Deserialize`,
and `Default` ?

After applying this attribute on a local fork of Bevy, I was able to
deserialize my UI tree exactly as intended with minimal markup in my
JSON files.

There might be a reason not to do this that I am not aware of, I tried
looking for similar past issues but could not find much conversation
about `#[serde(default)]`. Documentation on this attribute can be found
[here](https://serde.rs/container-attrs.html#default).

> #[serde(default = "path")]
>
> When deserializing, any missing fields should be filled in from the
object returned by the given function or method. The function must be
callable as fn() -> T. For example default = "my_default" would invoke
my_default() and default = "SomeTrait::some_default" would invoke
SomeTrait::some_default(). Only allowed on structs.


## Testing

I did not write any formal tests for this. Informally, I simply added
`#[serde(default)]` to `Node` to a local fork of Bevy and successfully
deserialized an instance of `Node` with default values not specified in
my JSON file.

## Sample JSON

Note how I only needed to specify 4/39 fields for `Node`. Upon
deserialization, `serde` invoked `Node::default()` to populate the
missing fields.

```c
{
    "UiRoot": {
        "Node": {
            "height": {"Percent": 100.0},
            "width": {"Percent": 100.0},
            "border": {"left": {"Px": 5.0}, "right": {"Px": 5.0}, "top": {"Px": 5.0}, "bottom": {"Px": 5.0}},
            "flex_direction": "Row"
        },
        "BorderColor": {"Srgba": {"red": 1.0, "green": 0.0, "blue": 0.0, "alpha": 1.0}},
        "Children": ["CreateGameButton"]
    },
    "CreateGameButton": {
        "Node": {
            "height": {"Percent": 25.0},
            "width": {"Percent": 25.0},
            "border": {"left": {"Px": 5.0}, "right": {"Px": 5.0}, "top": {"Px": 5.0}, "bottom": {"Px": 5.0}},
            "flex_direction": "Row"
        },
        "BorderColor": {"Srgba": {"red": 0.0, "green": 1.0, "blue": 0.0, "alpha": 1.0}},
        "Interaction": "None"
    }
}

```

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
T
T.J. Given committed
4e403b615e08843ca546362a9f369e54300979e2
Parent: 055f0f5
Committed by GitHub <noreply@github.com> on 5/22/2026, 2:27:23 PM