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

[Merged by Bors] - remove blanket Serialize + Deserialize requirement for Reflect on generic types #5197

Conversation

jakobhellermann
Copy link
Contributor

@jakobhellermann jakobhellermann commented Jul 4, 2022

Objective

Some generic types like Option<T>, Vec<T> and HashMap<K, V> implement Reflect when where their generic types T/K/V implement Serialize + for<'de> Deserialize<'de>.
This is so that in their GetTypeRegistration impl they can insert the ReflectSerialize and ReflectDeserialize type data structs.

This has the annoying side effect that if your struct contains a Option<NonSerdeStruct> you won't be able to derive reflect (#4054).

Solution

  • remove the Serialize + Deserialize bounds on wrapper types
    • this means that ReflectSerialize and ReflectDeserialize will no longer be inserted even for .register::<Option<DoesImplSerde>>()
  • add register_type_data<T, D> shorthand for registry.get_mut(T).insert(D::from_type<T>())
  • require users to register their specific generic types and the serde types separately like
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

I believe this is the best we can do for extensibility and convenience without specialization.

Changelog

  • .register_type for generic types like Option<T>, Vec<T>, HashMap<K, V> will no longer insert ReflectSerialize and ReflectDeserialize type data. Instead you need to register it separately for concrete generic types like so:
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

TODO: more docs and tweaks to the scene example to demonstrate registering generic types.

@jakobhellermann jakobhellermann added C-Feature A new feature, making something new possible A-Scenes Serialized ECS data stored on the disk A-Reflection Runtime information about types and removed A-Scenes Serialized ECS data stored on the disk labels Jul 4, 2022
@alice-i-cecile
Copy link
Member

Changes so far LGTM; this is much nicer and matches my own experiments.

  1. add register_type_data<T, D> shorthand for registry.get_mut(T).insert(D::from_type<T>()) I'm not seeing this; I take it this is not yet implemented?
  2. Can you toss in a Reflect / FromReflect impl for Result to match Option?

@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide and removed C-Feature A new feature, making something new possible labels Jul 4, 2022
@alice-i-cecile alice-i-cecile added this to the Bevy 0.8 milestone Jul 4, 2022
@jakobhellermann
Copy link
Contributor Author

1. `add register_type_data<T, D> shorthand for registry.get_mut(T).insert(D::from_type<T>())` I'm not seeing this; I take it this is not yet implemented?

Right, forgot to push that.

2. Can you toss in a `Reflect` / `FromReflect` impl for `Result` to match `Option`?

Done.

@alice-i-cecile
Copy link
Member

@jakobhellermann this is in the milestone and I'd like to land it; can you do a brief cleanup pass?

@alice-i-cecile
Copy link
Member

@PROMETHIA-27 @MrGVSV reviews please :)

Copy link
Member

@MrGVSV MrGVSV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! A few nitpicks but nothing major.

I think this is a good stopgap for more advanced ways of handling this type of thing in the future.

crates/bevy_reflect/src/type_registry.rs Outdated Show resolved Hide resolved
crates/bevy_reflect/src/type_registry.rs Show resolved Hide resolved
Copy link
Contributor

@PROMETHIA-27 PROMETHIA-27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! And I've just noticed that there was a big change to TypeData, gonna have to familiarize myself with that.

@jakobhellermann
Copy link
Contributor Author

I pushed a commit that removed the Option return and instead panics when called without registering the type first, and added the T: Reflect bound to be more consistent with the rest of the type registry.

We can have a separate discussion for whether we want to relax that bound and allow non-typed or non-reflect type data associations in the type registry or not.

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bors r+

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Jul 21, 2022
bors bot pushed a commit that referenced this pull request Jul 21, 2022
… generic types (#5197)

# Objective

Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.

This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (#4054).

## Solution

- remove the `Serialize + Deserialize` bounds on wrapper types
  - this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

```
I believe this is the best we can do for extensibility and convenience without specialization.


## Changelog

- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()
```

TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
@bors bors bot changed the title remove blanket Serialize + Deserialize requirement for Reflect on generic types [Merged by Bors] - remove blanket Serialize + Deserialize requirement for Reflect on generic types Jul 21, 2022
@bors bors bot closed this Jul 21, 2022
inodentry pushed a commit to IyesGames/bevy that referenced this pull request Aug 8, 2022
… generic types (bevyengine#5197)

# Objective

Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.

This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (bevyengine#4054).

## Solution

- remove the `Serialize + Deserialize` bounds on wrapper types
  - this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

```
I believe this is the best we can do for extensibility and convenience without specialization.


## Changelog

- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()
```

TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
@jakobhellermann jakobhellermann deleted the no-blanket-serde-requirement branch August 10, 2022 12:24
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
… generic types (bevyengine#5197)

# Objective

Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.

This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (bevyengine#4054).

## Solution

- remove the `Serialize + Deserialize` bounds on wrapper types
  - this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

```
I believe this is the best we can do for extensibility and convenience without specialization.


## Changelog

- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()
```

TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
… generic types (bevyengine#5197)

# Objective

Some generic types like `Option<T>`, `Vec<T>` and `HashMap<K, V>` implement `Reflect` when where their generic types `T`/`K`/`V` implement `Serialize + for<'de> Deserialize<'de>`.
This is so that in their `GetTypeRegistration` impl they can insert the `ReflectSerialize` and `ReflectDeserialize` type data structs.

This has the annoying side effect that if your struct contains a `Option<NonSerdeStruct>` you won't be able to derive reflect (bevyengine#4054).

## Solution

- remove the `Serialize + Deserialize` bounds on wrapper types
  - this means that `ReflectSerialize` and `ReflectDeserialize` will no longer be inserted even for `.register::<Option<DoesImplSerde>>()`
- add `register_type_data<T, D>` shorthand for `registry.get_mut(T).insert(D::from_type<T>())`
- require users to register their specific generic types **and the serde types** separately like
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()

```
I believe this is the best we can do for extensibility and convenience without specialization.


## Changelog

- `.register_type` for generic types like `Option<T>`, `Vec<T>`, `HashMap<K, V>` will no longer insert `ReflectSerialize` and `ReflectDeserialize` type data. Instead you need to register it separately for concrete generic types like so:
```rust
        .register_type::<Option<String>>()
        .register_type_data::<Option<String>, ReflectSerialize>()
        .register_type_data::<Option<String>, ReflectDeserialize>()
```

TODO: more docs and tweaks to the scene example to demonstrate registering generic types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Reflection Runtime information about types C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants