Commit graph

23 commits

Author SHA1 Message Date
Gino Valente
02fbf16c80 bevy_reflect: Add Reflect::into_reflect (#6502)
# Objective

Using `Reflect` we can easily switch between a specific reflection trait object, such as a `dyn Struct`, to a `dyn Reflect` object via `Reflect::as_reflect` or `Reflect::as_reflect_mut`.

```rust
fn do_something(value: &dyn Reflect) {/* ... */}

let foo: Box<dyn Struct> = Box::new(Foo::default());
do_something(foo.as_reflect());
```

However, there is no way to convert a _boxed_ reflection trait object to a `Box<dyn Reflect>`.

## Solution

Add a `Reflect::into_reflect` method which allows converting a boxed reflection trait object back into a boxed `Reflect` trait object.

```rust
fn do_something(value: Box<dyn Reflect>) {/* ... */}

let foo: Box<dyn Struct> = Box::new(Foo::default());
do_something(foo.into_reflect());
```

---

## Changelog

- Added `Reflect::into_reflect`
2022-11-07 02:11:16 +00:00
Hennadii Chernyshchyk
feebbc5ea9 Add reflect_owned (#6494)
# Objective

There is no way to gen an owned value of `Reflect`.

## Solution

Add it! This was originally a part of #6421, but @MrGVSV asked me to create a separate for it to implement reflect diffing.

---

## Changelog

### Added

- `Reflect::reflect_owned` to get an owned version of `Reflect`.
2022-11-06 16:58:38 +00:00
Gino Valente
3c2ac3651f bevy_reflect: Update Reflection documentation (#5841)
# Objective

The documentation on `Reflect` doesn't account for the recently added reflection traits: [`Array`](https://github.com/bevyengine/bevy/pull/4701) and [`Enum`](https://github.com/bevyengine/bevy/pull/4761).

## Solution

Updated the documentation for `Reflect` to account for the `Array` and `Enum`.


Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-09-02 16:17:45 +00:00
Gino Valente
15826d6019 bevy_reflect: Reflect enums (#4761)
# Objective

> This is a revival of #1347. Credit for the original PR should go to @Davier.

Currently, enums are treated as `ReflectRef::Value` types by `bevy_reflect`. Obviously, there needs to be better a better representation for enums using the reflection API.

## Solution

Based on prior work from @Davier, an `Enum` trait has been added as well as the ability to automatically implement it via the `Reflect` derive macro. This allows enums to be expressed dynamically:

```rust
#[derive(Reflect)]
enum Foo {
  A,
  B(usize),
  C { value: f32 },
}

let mut foo = Foo::B(123);
assert_eq!("B", foo.variant_name());
assert_eq!(1, foo.field_len());

let new_value = DynamicEnum::from(Foo::C { value: 1.23 });
foo.apply(&new_value);
assert_eq!(Foo::C{value: 1.23}, foo);
```

### Features

#### Derive Macro

Use the `#[derive(Reflect)]` macro to automatically implement the `Enum` trait for enum definitions. Optionally, you can use `#[reflect(ignore)]` with both variants and variant fields, just like you can with structs. These ignored items will not be considered as part of the reflection and cannot be accessed via reflection.

```rust
#[derive(Reflect)]
enum TestEnum {
  A,
  // Uncomment to ignore all of `B`
  // #[reflect(ignore)]
  B(usize),
  C {
    // Uncomment to ignore only field `foo` of `C`
    // #[reflect(ignore)]
    foo: f32,
    bar: bool,
  },
}
```

#### Dynamic Enums

Enums may be created/represented dynamically via the `DynamicEnum` struct. The main purpose of this struct is to allow enums to be deserialized into a partial state and to allow dynamic patching. In order to ensure conversion from a `DynamicEnum` to a concrete enum type goes smoothly, be sure to add `FromReflect` to your derive macro.

```rust
let mut value = TestEnum::A;

// Create from a concrete instance
let dyn_enum = DynamicEnum::from(TestEnum::B(123));

value.apply(&dyn_enum);
assert_eq!(TestEnum::B(123), value);

// Create a purely dynamic instance
let dyn_enum = DynamicEnum::new("TestEnum", "A", ());

value.apply(&dyn_enum);
assert_eq!(TestEnum::A, value);
```

#### Variants

An enum value is always represented as one of its variants— never the enum in its entirety.

```rust
let value = TestEnum::A;
assert_eq!("A", value.variant_name());

// Since we are using the `A` variant, we cannot also be the `B` variant
assert_ne!("B", value.variant_name());
```

All variant types are representable within the `Enum` trait: unit, struct, and tuple.

You can get the current type like:

```rust
match value.variant_type() {
  VariantType::Unit => println!("A unit variant!"),
  VariantType::Struct => println!("A struct variant!"),
  VariantType::Tuple => println!("A tuple variant!"),
}
```

> Notice that they don't contain any values representing the fields. These are purely tags.

If a variant has them, you can access the fields as well:

```rust
let mut value = TestEnum::C {
  foo: 1.23,
  bar: false
};

// Read/write specific fields
*value.field_mut("bar").unwrap() = true;

// Iterate over the entire collection of fields
for field in value.iter_fields() {
  println!("{} = {:?}", field.name(), field.value());
}
```

#### Variant Swapping

It might seem odd to group all variant types under a single trait (why allow `iter_fields` on a unit variant?), but the reason this was done ~~is to easily allow *variant swapping*.~~ As I was recently drafting up the **Design Decisions** section, I discovered that other solutions could have been made to work with variant swapping. So while there are reasons to keep the all-in-one approach, variant swapping is _not_ one of them.

```rust
let mut value: Box<dyn Enum> = Box::new(TestEnum::A);
value.set(Box::new(TestEnum::B(123))).unwrap();
```

#### Serialization

Enums can be serialized and deserialized via reflection without needing to implement `Serialize` or `Deserialize` themselves (which can save thousands of lines of generated code). Below are the ways an enum can be serialized.

> Note, like the rest of reflection-based serialization, the order of the keys in these representations is important!

##### Unit

```json
{
  "type": "my_crate::TestEnum",
  "enum": {
    "variant": "A"
  }
}
```

##### Tuple

```json
{
  "type": "my_crate::TestEnum",
  "enum": {
    "variant": "B",
    "tuple": [
      {
        "type": "usize",
        "value": 123
      }
    ]
  }
}
```

<details>
<summary>Effects on Option</summary>

This ends up making `Option` look a little ugly:

```json
{
  "type": "core::option::Option<usize>",
  "enum": {
    "variant": "Some",
    "tuple": [
      {
        "type": "usize",
        "value": 123
      }
    ]
  }
}
```


</details>

##### Struct

```json
{
  "type": "my_crate::TestEnum",
  "enum": {
    "variant": "C",
    "struct": {
      "foo": {
        "type": "f32",
        "value": 1.23
      },
      "bar": {
        "type": "bool",
        "value": false
      }
    }
  }
}
```

## Design Decisions

<details>
<summary><strong>View Section</strong></summary>

This section is here to provide some context for why certain decisions were made for this PR, alternatives that could have been used instead, and what could be improved upon in the future.

### Variant Representation

One of the biggest decisions was to decide on how to represent variants. The current design uses a "all-in-one" design where unit, tuple, and struct variants are all simultaneously represented by the `Enum` trait. This is not the only way it could have been done, though.

#### Alternatives

##### 1. Variant Traits

One way of representing variants would be to define traits for each variant, implementing them whenever an enum featured at least one instance of them. This would allow us to define variants like:

```rust
pub trait Enum: Reflect {
  fn variant(&self) -> Variant;
}

pub enum Variant<'a> {
    Unit,
    Tuple(&'a dyn TupleVariant),
    Struct(&'a dyn StructVariant),
}

pub trait TupleVariant {
  fn field_len(&self) -> usize;
  // ...
}
```

And then do things like:

```rust
fn get_tuple_len(foo: &dyn Enum) -> usize {
  match foo.variant() {
    Variant::Tuple(tuple) => tuple.field_len(),
    _ => panic!("not a tuple variant!")
  }
}
```

The reason this PR does not go with this approach is because of the fact that variants are not separate types. In other words, we cannot implement traits on specific variants— these cover the *entire* enum. This means we offer an easy footgun:

```rust
let foo: Option<i32> = None;
let my_enum = Box::new(foo) as Box<dyn TupleVariant>;
```

Here, `my_enum` contains `foo`, which is a unit variant. However, since we need to implement `TupleVariant` for `Option` as a whole, it's possible to perform such a cast. This is obviously wrong, but could easily go unnoticed. So unfortunately, this makes it not a good candidate for representing variants.

##### 2. Variant Structs

To get around the issue of traits necessarily needing to apply to both the enum and its variants, we could instead use structs that are created on a per-variant basis. This was also considered but was ultimately [[removed](71d27ab3c6) due to concerns about allocations.

 Each variant struct would probably look something like:

```rust
pub trait Enum: Reflect {
  fn variant_mut(&self) -> VariantMut;
}

pub enum VariantMut<'a> {
    Unit,
    Tuple(TupleVariantMut),
    Struct(StructVariantMut),
}

struct StructVariantMut<'a> {
  fields: Vec<&'a mut dyn Reflect>,
  field_indices: HashMap<Cow<'static, str>, usize>
}
```

This allows us to isolate struct variants into their own defined struct and define methods specifically for their use. It also prevents users from casting to it since it's not a trait. However, this is not an optimal solution. Both `field_indices` and `fields` will require an allocation (remember, a `Box<[T]>` still requires a `Vec<T>` in order to be constructed). This *might* be a problem if called frequently enough.

##### 3. Generated Structs

The original design, implemented by @Davier, instead generates structs specific for each variant. So if we had a variant path like `Foo::Bar`, we'd generate a struct named `FooBarWrapper`. This would be newtyped around the original enum and forward tuple or struct methods to the enum with the chosen variant.

Because it involved using the `Tuple` and `Struct` traits (which are also both bound on `Reflect`), this meant a bit more code had to be generated. For a single struct variant with one field, the generated code amounted to ~110LoC. However, each new field added to that variant only added ~6 more LoC.

In order to work properly, the enum had to be transmuted to the generated struct:

```rust
fn variant(&self) -> crate::EnumVariant<'_> {
  match self {
    Foo::Bar {value: i32} => {
      let wrapper_ref = unsafe { 
        std::mem::transmute::<&Self, &FooBarWrapper>(self) 
      };
      crate::EnumVariant::Struct(wrapper_ref as &dyn crate::Struct)
    }
  }
}
```

This works because `FooBarWrapper` is defined as `repr(transparent)`.

Out of all the alternatives, this would probably be the one most likely to be used again in the future. The reasons for why this PR did not continue to use it was because:

* To reduce generated code (which would hopefully speed up compile times)
* To avoid cluttering the code with generated structs not visible to the user
* To keep bevy_reflect simple and extensible (these generated structs act as proxies and might not play well with current or future systems)
* To avoid additional unsafe blocks
* My own misunderstanding of @Davier's code

That last point is obviously on me. I misjudged the code to be too unsafe and unable to handle variant swapping (which it probably could) when I was rebasing it. Looking over it again when writing up this whole section, I see that it was actually a pretty clever way of handling variant representation.

#### Benefits of All-in-One

As stated before, the current implementation uses an all-in-one approach. All variants are capable of containing fields as far as `Enum` is concerned. This provides a few benefits that the alternatives do not (reduced indirection, safer code, etc.).

The biggest benefit, though, is direct field access. Rather than forcing users to have to go through pattern matching, we grant direct access to the fields contained by the current variant. The reason we can do this is because all of the pattern matching happens internally. Getting the field at index `2` will automatically return `Some(...)` for the current variant if it has a field at that index or `None` if it doesn't (or can't).

This could be useful for scenarios where the variant has already been verified or just set/swapped (or even where the type of variant doesn't matter):

```rust
let dyn_enum: &mut dyn Enum = &mut Foo::Bar {value: 123};
// We know it's the `Bar` variant
let field = dyn_enum.field("value").unwrap();
```

Reflection is not a type-safe abstraction— almost every return value is wrapped in `Option<...>`. There are plenty of places to check and recheck that a value is what Reflect says it is. Forcing users to have to go through `match` each time they want to access a field might just be an extra step among dozens of other verification processes.

 Some might disagree, but ultimately, my view is that the benefit here is an improvement to the ergonomics and usability of reflected enums.

</details>

---

## Changelog

### Added

* Added `Enum` trait
* Added `Enum` impl to `Reflect` derive macro
* Added `DynamicEnum` struct
  * Added `DynamicVariant`
* Added `EnumInfo`
  * Added `VariantInfo`
    * Added `StructVariantInfo`
    * Added `TupleVariantInfo`
    * Added `UnitVariantInfo`
* Added serializtion/deserialization support for enums
  * Added `EnumSerializer`

* Added `VariantType`
* Added `VariantFieldIter`
* Added `VariantField`
* Added `enum_partial_eq(...)`
* Added `enum_hash(...)`

### Changed

* `Option<T>` now implements `Enum`
* `bevy_window` now depends on `bevy_reflect`
  * Implemented `Reflect` and `FromReflect` for `WindowId`
* Derive `FromReflect` on `PerspectiveProjection`
* Derive `FromReflect` on `OrthographicProjection`
* Derive `FromReflect` on `WindowOrigin`
* Derive `FromReflect` on `ScalingMode`
* Derive `FromReflect` on `DepthCalculation`


## Migration Guide

* Enums no longer need to be treated as values and usages of `#[reflect_value(...)]` can be removed or replaced by `#[reflect(...)]`
* Enums (including `Option<T>`) now take a different format when serializing. The format is described above, but this may cause issues for existing scenes that make use of enums. 

---

Also shout out to @nicopap for helping clean up some of the code here! It's a big feature so help like this is really appreciated!

Co-authored-by: Gino Valente <gino.valente.code@gmail.com>
2022-08-02 22:14:41 +00:00
James Liu
5498ef81fb bevy_reflect: support map insertion (#5173)
# Objective

This is a rebase of #3701 which is currently scheduled for 0.8 but is marked for adoption.

> Fixes https://github.com/bevyengine/bevy/discussions/3609

## Solution
> - add an `insert_boxed()` method on the `Map` trait
> - implement it for `HashMap` using a new `FromReflect` generic bound
> - add a `map_apply()` helper method to implement `Map::apply()`, that inserts new values instead of ignoring them


---

## Changelog
TODO

Co-authored-by: james7132 <contact@jamessliu.com>
2022-07-04 13:04:19 +00:00
PROMETHIA-27
c27a3cff6d Make Reflect safe to implement (#5010)
# Objective

Currently, `Reflect` is unsafe to implement because of a contract in which `any` and `any_mut` must return `self`, or `downcast` will cause UB. This PR makes `Reflect` safe, makes `downcast` not use unsafe, and eliminates this contract. 

## Solution

This PR adds a method to `Reflect`, `any`. It also renames the old `any` to `as_any`.
`any` now takes a `Box<Self>` and returns a `Box<dyn Any>`. 

---

## Changelog

### Added:
- `any()` method
- `represents()` method

### Changed:
- `Reflect` is now a safe trait
- `downcast()` is now safe
- The old `any` is now called `as_any`, and `any_mut` is now `as_mut_any`

## Migration Guide

- Reflect derives should not have to change anything
- Manual reflect impls will need to remove the `unsafe` keyword, add `any()` implementations, and rename the old `any` and `any_mut` to `as_any` and `as_mut_any`.
- Calls to `any`/`any_mut` must be changed to `as_any`/`as_mut_any`

## Points of discussion:

- Should renaming `any` be avoided and instead name the new method `any_box`?
- ~~Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.~~
- ~~Could/should `is` and `type_id()` be implemented differently? For example, moving `is` onto `Reflect` as an `fn(&self, TypeId) -> bool`~~


Co-authored-by: PROMETHIA-27 <42193387+PROMETHIA-27@users.noreply.github.com>
2022-06-27 16:52:25 +00:00
Gino Valente
e6f34ba47f bevy_reflect: Add statically available type info for reflected types (#4042)
# Objective

> Resolves #4504

It can be helpful to have access to type information without requiring an instance of that type. Especially for `Reflect`, a lot of the gathered type information is known at compile-time and should not necessarily require an instance.

## Solution

Created a dedicated `TypeInfo` enum to store static type information. All types that derive `Reflect` now also implement the newly created `Typed` trait:

```rust
pub trait Typed: Reflect {
  fn type_info() -> &'static TypeInfo;
}
```

> Note: This trait was made separate from `Reflect` due to `Sized` restrictions.

If you only have access to a `dyn Reflect`, just call `.get_type_info()` on it. This new trait method on `Reflect` should return the same value as if you had called it statically. 

If all you have is a `TypeId` or type name, you can get the `TypeInfo` directly from the registry using the `TypeRegistry::get_type_info` method (assuming it was registered).

### Usage

Below is an example of working with `TypeInfo`. As you can see, we don't have to generate an instance of `MyTupleStruct` in order to get this information.

```rust
#[derive(Reflect)]
struct MyTupleStruct(usize, i32, MyStruct);

let info = MyTupleStruct::type_info();
if let TypeInfo::TupleStruct(info) = info {
  assert!(info.is::<MyTupleStruct>());
  assert_eq!(std::any::type_name::<MyTupleStruct>(), info.type_name());
  assert!(info.field_at(1).unwrap().is::<i32>());
} else {
  panic!("Expected `TypeInfo::TupleStruct`");
}
```

### Manual Implementations

It's not recommended to manually implement `Typed` yourself, but if you must, you can use the `TypeInfoCell` to automatically create and manage the static `TypeInfo`s for you (which is very helpful for blanket/generic impls):

```rust
use bevy_reflect::{Reflect, TupleStructInfo, TypeInfo, UnnamedField};
use bevy_reflect::utility::TypeInfoCell;

struct Foo<T: Reflect>(T);

impl<T: Reflect> Typed for Foo<T> {
  fn type_info() -> &'static TypeInfo {
    static CELL: TypeInfoCell = TypeInfoCell::generic();
    CELL.get_or_insert::<Self, _>(|| {
      let fields = [UnnamedField:🆕:<T>()];
      let info = TupleStructInfo:🆕:<Self>(&fields);
      TypeInfo::TupleStruct(info)
    })
  }
}
```

## Benefits

One major benefit is that this opens the door to other serialization methods. Since we can get all the type info at compile time, we can know how to properly deserialize something like:

```rust
#[derive(Reflect)]
struct MyType {
  foo: usize,
  bar: Vec<String>
}

// RON to be deserialized:
(
  type: "my_crate::MyType", // <- We now know how to deserialize the rest of this object
  value: {
    // "foo" is a value type matching "usize"
    "foo": 123,
    // "bar" is a list type matching "Vec<String>" with item type "String"
    "bar": ["a", "b", "c"]
  }
)
```

Not only is this more compact, but it has better compatibility (we can change the type of `"foo"` to `i32` without having to update our serialized data).

Of course, serialization/deserialization strategies like this may need to be discussed and fully considered before possibly making a change. However, we will be better equipped to do that now that we can access type information right from the registry.

## Discussion

Some items to discuss:

1. Duplication. There's a bit of overlap with the existing traits/structs since they require an instance of the type while the type info structs do not (for example, `Struct::field_at(&self, index: usize)` and `StructInfo::field_at(&self, index: usize)`, though only `StructInfo` is accessible without an instance object). Is this okay, or do we want to handle it in another way?
2. Should `TypeInfo::Dynamic` be removed? Since the dynamic types don't have type information available at runtime, we could consider them `TypeInfo::Value`s (or just even just `TypeInfo::Struct`). The intention with `TypeInfo::Dynamic` was to keep the distinction from these dynamic types and actual structs/values since users might incorrectly believe the methods of the dynamic type's info struct would map to some contained data (which isn't possible statically).
4. General usefulness of this change, including missing/unnecessary parts.
5. Possible changes to the scene format? (One possible issue with changing it like in the example above might be that we'd have to be careful when handling generic or trait object types.)

## Compile Tests

I ran a few tests to compare compile times (as suggested [here](https://github.com/bevyengine/bevy/pull/4042#discussion_r876408143)). I toggled `Reflect` and `FromReflect` derive macros using `cfg_attr` for both this PR (aa5178e773) and main (c309acd432).

<details>
<summary>See More</summary>

The test project included 250 of the following structs (as well as a few other structs):

```rust
#[derive(Default)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[cfg_attr(feature = "from_reflect", derive(FromReflect))]
pub struct Big001 {
    inventory: Inventory,
    foo: usize,
    bar: String,
    baz: ItemDescriptor,
    items: [Item; 20],
    hello: Option<String>,
    world: HashMap<i32, String>,
    okay: (isize, usize, /* wesize */),
    nope: ((String, String), (f32, f32)),
    blah: Cow<'static, str>,
}
```

> I don't know if the compiler can optimize all these duplicate structs away, but I think it's fine either way. We're comparing times, not finding the absolute worst-case time.

I only ran each build 3 times using `cargo build --timings` (thank you @devil-ira), each of which were preceeded by a `cargo clean --package bevy_reflect_compile_test`. 

Here are the times I got:

| Test                             | Test 1 | Test 2 | Test 3 | Average |
| -------------------------------- | ------ | ------ | ------ | ------- |
| Main                             | 1.7s   | 3.1s   | 1.9s   | 2.33s   |
| Main + `Reflect`                 | 8.3s   | 8.6s   | 8.1s   | 8.33s   |
| Main + `Reflect` + `FromReflect` | 11.6s  | 11.8s  | 13.8s  | 12.4s   |
| PR                               | 3.5s   | 1.8s   | 1.9s   | 2.4s    |
| PR + `Reflect`                   | 9.2s   | 8.8s   | 9.3s   | 9.1s    |
| PR + `Reflect` + `FromReflect`   | 12.9s  | 12.3s  | 12.5s  | 12.56s  |

</details>

---

## Future Work

Even though everything could probably be made `const`, we unfortunately can't. This is because `TypeId::of::<T>()` is not yet `const` (see https://github.com/rust-lang/rust/issues/77125). When it does get stabilized, it would probably be worth coming back and making things `const`. 

Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-06-09 21:18:15 +00:00
Gino Valente
2f5591ff8c bevy_reflect: Improve debug formatting for reflected types (#4218)
# Objective

Debugging reflected types can be somewhat frustrating since all `dyn Reflect` trait objects return something like `Reflect(core::option::Option<alloc::string::String>)`.

It would be much nicer to be able to see the actual value— or even use a custom `Debug` implementation.

## Solution

Added `Reflect::debug` which allows users to customize the debug output. It sets defaults for all `ReflectRef` subtraits and falls back to `Reflect(type_name)` if no `Debug` implementation was registered.

To register a custom `Debug` impl, users can add `#[reflect(Debug)]` like they can with other traits.

### Example

Using the following structs:

```rust
#[derive(Reflect)]
pub struct Foo {
    a: usize,
    nested: Bar,
    #[reflect(ignore)]
    _ignored: NonReflectedValue,
}

#[derive(Reflect)]
pub struct Bar {
    value: Vec2,
    tuple_value: (i32, String),
    list_value: Vec<usize>,
    // We can't determine debug formatting for Option<T> yet
    unknown_value: Option<String>,
    custom_debug: CustomDebug
}

#[derive(Reflect)]
#[reflect(Debug)]
struct CustomDebug;

impl Debug for CustomDebug {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "This is a custom debug!")
    }
}

pub struct NonReflectedValue {
    _a: usize,
}
```

We can do:

```rust
let value = Foo {
  a: 1,
  _ignored: NonReflectedValue { _a: 10 },
  nested: Bar {
    value: Vec2::new(1.23, 3.21),
    tuple_value: (123, String::from("Hello")),
    list_value: vec![1, 2, 3],
    unknown_value: Some(String::from("World")),
    custom_debug: CustomDebug
  },
};
let reflected_value: &dyn Reflect = &value;
println!("{:#?}", reflected_value)
```

Which results in:

```rust
Foo {
  a: 2,
  nested: Bar {
    value: Vec2(
      1.23,
      3.21,
    ),
    tuple_value: (
      123,
      "Hello",
    ),
    list_value: [
      1,
      2,
      3,
    ],
    unknown_value: Reflect(core::option::Option<alloc::string::String>),
    custom_debug: This is a custom debug!,
  },
}
```

Notice that neither `Foo` nor `Bar` implement `Debug`, yet we can still deduce it. This might be a concern if we're worried about leaking internal values. If it is, we might want to consider a way to exclude fields (possibly with a `#[reflect(hide)]` macro) or make it purely opt in (as opposed to the default implementation automatically handled by ReflectRef subtraits).

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-05-30 16:41:31 +00:00
MrGVSV
15acd6f45d bevy_reflect: Small refactor and default Reflect methods (#4739)
# Objective

Quick followup to #4712.

While updating some [other PRs](https://github.com/bevyengine/bevy/pull/4218), I realized the `ReflectTraits` struct could be improved. The issue with the current implementation is that `ReflectTraits::get_xxx_impl(...)` returns just the _logic_ to the corresponding `Reflect` trait method, rather than the entire function.

This makes it slightly more annoying to manage since the variable names need to be consistent across files. For example, `get_partial_eq_impl` uses a `value` variable. But the name "value" isn't defined in the `get_partial_eq_impl` method, it's defined in three other methods in a completely separate file.

It's not likely to cause any bugs if we keep it as it is since differing variable names will probably just result in a compile error (except in very particular cases). But it would be useful to someone who wanted to edit/add/remove a method.

## Solution

Made `get_hash_impl`, `get_partial_eq_impl` and `get_serialize_impl` return the entire method implementation for `reflect_hash`, `reflect_partial_eq`, and `serializable`, respectively.

As a result of this, those three `Reflect` methods were also given default implementations. This was fairly simple to do since all three could just be made to return `None`.

---

## Changelog

* Small cleanup/refactor to `ReflectTraits` in `bevy_reflect_derive`
* Gave `Reflect::reflect_hash`, `Reflect::reflect_partial_eq`, and `Reflect::serializable` default implementations
2022-05-18 12:26:11 +00:00
MrGVSV
acbee7795d bevy_reflect: Reflect arrays (#4701)
# Objective

> ℹ️ **Note**: This is a rebased version of #2383. A large portion of it has not been touched (only a few minor changes) so that any additional discussion may happen here. All credit should go to @NathanSWard for their work on the original PR.

- Currently reflection is not supported for arrays.
- Fixes #1213

## Solution

* Implement reflection for arrays via the `Array` trait.
* Note, `Array` is different from `List` in the way that you cannot push elements onto an array as they are statically sized.
* Now `List` is defined as a sub-trait of `Array`.

---

## Changelog

* Added the `Array` reflection trait
* Allows arrays up to length 32 to be reflected via the `Array` trait

## Migration Guide

* The `List` trait now has the `Array` supertrait. This means that `clone_dynamic` will need to specify which version to use:
  ```rust
  // Before
  let cloned = my_list.clone_dynamic();
  // After
  let cloned = List::clone_dynamic(&my_list);
  ```
* All implementers of `List` will now need to implement `Array` (this mostly involves moving the existing methods to the `Array` impl)

Co-authored-by: NathanW <nathansward@comcast.net>
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-13 01:13:30 +00:00
MrGVSV
5047e1f08e bevy_reflect: Add as_reflect and as_reflect_mut (#4350)
# Objective

Trait objects that have `Reflect` as a supertrait cannot be upcast to a `dyn Reflect`.

Attempting something like:

```rust
trait MyTrait: Reflect {
  // ...
}

fn foo(value: &dyn MyTrait) {
  let reflected = value as &dyn Reflect; // Error!
  // ...
}
```

Results in `error[E0658]: trait upcasting coercion is experimental`.

The reason this is important is that a lot of `bevy_reflect` methods require a `&dyn Reflect`. This is trivial with concrete types, but if we don't know the concrete type (we only have the trait object), we can't use these methods. For example, we couldn't create a `ReflectSerializer` for the type since it expects a `&dyn Reflect` value— even though we should be able to.

## Solution

Add `as_reflect` and `as_reflect_mut` to `Reflect` to allow upcasting to a `dyn Reflect`:

```rust
trait MyTrait: Reflect {
  // ...
}

fn foo(value: &dyn MyTrait) {
  let reflected = value.as_reflect();
  // ...
}
```

## Alternatives

We could defer this type of logic to the crate/user. They can add these methods to their trait in the same exact way we do here. The main benefit of doing it ourselves is it makes things convenient for them (especially when using the derive macro).

We could also create an `AsReflect` trait with a blanket impl over all reflected types, however, I could not get that to work for trait objects since they aren't sized.

---

## Changelog

- Added trait method `Reflect::as_reflect(&self)`
- Added trait method `Reflect::as_reflect_mut(&mut self)`

## Migration Guide

- Manual implementors of `Reflect` will need to add implementations for the methods above (this should be pretty easy as most cases just need to return `self`)
2022-04-25 13:54:48 +00:00
dataphract
f073b2d7f3 document more of bevy_reflect (#3655)
This adds documentation for:

- The trait methods of `Reflect` and its subtraits
- The `partial_eq` and `apply` functions for `Map` et al.
- `DynamicList` and `DynamicMap`
- `TypeRegistry` and related types & traits
- `GetPath`, including an explanation of path string syntax

among other things.

Still to be documented are the various macros and `bevy_reflect::serde`.
2022-01-14 19:09:44 +00:00
dataphract
4b4dbb021f document Struct, TupleStruct and Tuple (#3081)
# Objective

These traits are undocumented on `main`.

## Solution

Now they have docs! Included are examples for each trait and their corresponding `GetTypeField` trait. The docs also mention that `#[derive(Reflect)]` will automatically derive the correct subtrait on structs and tuple structs.
2022-01-08 20:45:24 +00:00
davier
06d9384447 Add FromReflect trait to convert dynamic types to concrete types (#1395)
Dynamic types (`DynamicStruct`, `DynamicTupleStruct`, `DynamicTuple`, `DynamicList` and `DynamicMap`) are used when deserializing scenes, but currently they can only be applied to existing concrete types. This leads to issues when trying to spawn non trivial deserialized scene.
For components, the issue is avoided by requiring that reflected components implement ~~`FromResources`~~ `FromWorld` (or `Default`). When spawning, a new concrete type is created that way, and the dynamic type is applied to it. Unfortunately, some components don't have any valid implementation of these traits.
In addition, any `Vec` or `HashMap` inside a component will panic when a dynamic type is pushed into it (for instance, `Text` panics when adding a text section).

To solve this issue, this PR adds the `FromReflect` trait that creates a concrete type from a dynamic type that represent it, derives the trait alongside the `Reflect` trait, drops the ~~`FromResources`~~ `FromWorld` requirement on reflected components, ~~and enables reflection for UI and Text bundles~~. It also adds the requirement that fields ignored with `#[reflect(ignore)]` implement `Default`, since we need to initialize them somehow.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2021-12-26 18:49:01 +00:00
Christopher Durham
a60fe30ada Avoid some format! into immediate format! (#2913)
# Objective

- Avoid usages of `format!` that ~immediately get passed to another `format!`. This avoids a temporary allocation and is just generally cleaner.

## Solution

- `bevy_derive::shader_defs` does a `format!("{}", val.to_string())`, which is better written as just `format!("{}", val)`
- `bevy_diagnostic::log_diagnostics_plugin` does a `format!("{:>}", format!(...))`, which is better written as `format!("{:>}", format_args!(...))`
- `bevy_ecs::schedule` does `tracing::info!(..., name = &*format!("{:?}", val))`, which is better written with the tracing shorthand `tracing::info!(..., name = ?val)`
- `bevy_reflect::reflect` does `f.write_str(&format!(...))`, which is better written as `write!(f, ...)` (this could also be written using `f.debug_tuple`, but I opted to maintain alt debug behavior)
- `bevy_reflect::serde::{ser, de}` do `serde::Error::custom(format!(...))`, which is better written as `Error::custom(format_args!(...))`, as `Error::custom` takes `impl Display` and just immediately calls `format!` again
2021-10-06 18:34:33 +00:00
François
fcf8fafa71 fix dead intra links in doc on Input and Reflect (#2007)
fix a few dead links

* Links in `Input` missed a refactor
* `Reflect::downcast` can't use the intra doc link format, as it's not a link to a trait function, but to a function implemented on `dyn Reflect`

noticed in https://github.com/bevyengine/bevy/pull/1781#discussion_r619777879
2021-04-25 17:24:09 +00:00
Alice Cecile
e4e32598a9 Cargo fmt with unstable features (#1903)
Fresh version of #1670 off the latest main.

Mostly fixing documentation wrapping.
2021-04-21 23:19:34 +00:00
Carter Anderson
5fedb6029a Make Reflect impls unsafe (Reflect::any must return self) (#1679)
Fixes #1100 

Implementors must make sure that `Reflect::any` and `Reflect::any_mut` both return the `self` reference passed in (both for logical correctness and downcast safety).
2021-03-17 22:46:46 +00:00
Carter Anderson
b17f8a4bce format comments (#1612)
Uses the new unstable comment formatting features added to rustfmt.toml.
2021-03-11 00:27:30 +00:00
Adamaq01
4a0837048c
Made ReflectMut::Tuple enum variant use a mutable reference (#1226) 2021-01-08 18:29:03 -08:00
TehPers
5e7456115a
Implement Reflect for tuples up to length 12 (#1218)
Add Reflect impls for tuples up to length 12
2021-01-07 19:50:09 -08:00
Nathan Stocks
3cee95e59a
Rename reflect 'hash' method to 'reflect_hash' and partial_eq to reflect_partial_eq (#954)
* Rename reflect 'hash' method to 'reflect_hash' to avoid colliding with std:#️⃣:Hash::hash to resolve #943.

* Rename partial_eq to reflect_partial_eq to avoid collisions with implementations of PartialEq on primitives.
2020-12-01 11:15:07 -08:00
Carter Anderson
72b2fc9843
Bevy Reflection (#926)
Bevy Reflection
2020-11-27 16:39:59 -08:00